The following patch decreases existing code size degradation on ARM by
permitting a special case of early clobber without reloads, for example,
for pattern
;; Use `&' and then `0' to prevent the operands 0 and 1 being the same
(define_insn "*arm_mulsi3"
[(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
(mult:SI (match_operand:SI 2 "s_register_operand" "r,r")
(match_operand:SI 1 "s_register_operand" "%0,r")))]
"TARGET_32BIT && !arm_arch6"
"mul%?\\t%0, %2, %1"
[(set_attr "insn" "mul")
(set_attr "predicable" "yes")]
)
It required complete rewriting code dealing with early clobbers in LRA.
The patch was successfully bootstrapped on x86-64, ia64, and ppc.
2011-07-26 Vladimir Makarov <vmaka...@redhat.com>
* lra-assign.c (setup_live_pseudos_and_spill_after_equiv_moves):
Remove the dead code.
* lra-constraints.c (goal_alternative*): Rename to goal_alt...
(goal_early_clobbered_nops_num, goal_early_clobbered_nops):
Remove.
(goal_alt_dont_inherit_ops_num, goal_alt_dont_inherit_ops): New
static variables.
(uses_hard_regs_p): New function.
(process_alt_operands): Rename curr_alternative to curr_alt...
Rename curr_early_clobbered_regs[_num] to
early_clobbered_regs[_num]. Add code for matching with early
clobber. Add code to process and evaluate conflicts with early
clobbers. Set up goal_alt_dont_inherit_ops_num,
goal_alt_dont_inherit_ops.
(early_clobber_reload_regs_num, early_clobber_reload_regs):
Remove.
(make_early_clobber_input_reload_reg, search_and_replace_reg):
Ditto.
s(create_early_clobber_reloads): Ditto.
(curr_insn_transform): Rename goal_alternative_matched to
goal_alt_matched. Setup dont_inherit flag for early clobber
reload pseudo. Don't call create_early_clobber_reloads.
Index: lra-assigns.c
===================================================================
--- lra-assigns.c (revision 175931)
+++ lra-assigns.c (working copy)
@@ -869,8 +869,6 @@
curr_regno >= 0;
curr_regno = lra_reg_info[curr_regno].next)
{
- IOR_HARD_REG_SET (conflict_set,
- lra_reg_info[curr_regno].conflict_hard_regs);
if (GET_MODE_SIZE (mode)
< GET_MODE_SIZE (lra_reg_info[curr_regno].biggest_mode))
mode = lra_reg_info[curr_regno].biggest_mode;
Index: lra-constraints.c
===================================================================
--- lra-constraints.c (revision 176001)
+++ lra-constraints.c (working copy)
@@ -802,7 +802,7 @@
outmode = lra_get_mode (curr_static_id->operand[out].mode, out_rtx);
if (inmode != outmode)
{
- /* Don't reuse the pseudos for inheritance -- they will bound. */
+ /* Don't reuse the pseudos for inheritance -- they will be bound. */
get_reload_reg (OP_IN, inmode, in_rtx, goal_class, "", &new_in_reg);
new_out_reg = lra_create_new_reg (outmode, out_rtx, goal_class, "");
}
@@ -1060,26 +1060,24 @@
/* The chosen reg class which should be used for the corresponding
operands. */
-static enum reg_class goal_alternative[MAX_RECOG_OPERANDS];
+static enum reg_class goal_alt[MAX_RECOG_OPERANDS];
/* True if the operand should be the same as another operand and the
another operand does not need a reload. */
-static bool goal_alternative_match_win[MAX_RECOG_OPERANDS];
+static bool goal_alt_match_win[MAX_RECOG_OPERANDS];
/* True if the operand does not need a reload. */
-static bool goal_alternative_win[MAX_RECOG_OPERANDS];
+static bool goal_alt_win[MAX_RECOG_OPERANDS];
/* True if the operand can be offsetable memory. */
-static bool goal_alternative_offmemok[MAX_RECOG_OPERANDS];
+static bool goal_alt_offmemok[MAX_RECOG_OPERANDS];
/* The number of operand to which given operand can be matched to. */
-static int goal_alternative_matches[MAX_RECOG_OPERANDS];
+static int goal_alt_matches[MAX_RECOG_OPERANDS];
+/* The number of elements in the following array. */
+static int goal_alt_dont_inherit_ops_num;
+/* Numbers of operands whose reload pseudos should not be inherited. */
+static int goal_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
/* True if the insn commutative operands should be swapped. */
-static bool goal_alternative_swapped;
-/* The number of elements in the following two arrays. */
-static int goal_early_clobbered_nops_num;
-/* Numbers of operands which are early clobbered registers. */
-static int goal_early_clobbered_nops[MAX_RECOG_OPERANDS];
-/* Biggest of mode of the early clobbered registers. */
-static enum machine_mode goal_early_clobbered_modes[MAX_RECOG_OPERANDS];
+static bool goal_alt_swapped;
/* The chosen insn alternative. */
-static int goal_alternative_number;
+static int goal_alt_number;
/* The following four variables are used to choose the best insn
alternative. They reflect finally characteristics of the best
@@ -1247,6 +1245,74 @@
return lra_get_elimation_hard_regno (hard_regno);
}
+/* Return TRUE if *LOC refers for a hard register from SET. */
+static bool
+uses_hard_regs_p (rtx *loc, HARD_REG_SET set)
+{
+ int i, j, x_hard_regno;
+ enum machine_mode mode;
+ rtx x;
+ const char *fmt;
+ enum rtx_code code;
+
+ if (*loc == NULL_RTX)
+ return false;
+ x = *loc;
+ code = GET_CODE (x);
+ mode = GET_MODE (x);
+ if (code == SUBREG)
+ {
+ loc = &SUBREG_REG (x);
+ x = SUBREG_REG (x);
+ code = GET_CODE (x);
+ if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
+ mode = GET_MODE (x);
+ }
+
+ if (REG_P (x))
+ {
+ x_hard_regno = REGNO (x);
+ if (x_hard_regno >= FIRST_PSEUDO_REGISTER)
+ x_hard_regno = reg_renumber[x_hard_regno];
+ return (x_hard_regno >= 0
+ && lra_hard_reg_set_intersection_p (x_hard_regno, mode, set));
+ }
+ if (MEM_P (x))
+ {
+ struct address ad;
+ enum machine_mode mode = GET_MODE (x);
+ rtx *addr_loc = &XEXP (x, 0);
+
+ extract_address_regs (mode, addr_loc, MEM, &ad);
+ if (ad.base_reg_loc != NULL)
+ {
+ if (uses_hard_regs_p (ad.base_reg_loc, set))
+ return true;
+ }
+ if (ad.index_reg_loc != NULL)
+ {
+ if (uses_hard_regs_p (ad.index_reg_loc, set))
+ return true;
+ }
+ }
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (uses_hard_regs_p (&XEXP (x, i), set))
+ return true;
+ }
+ else if (fmt[i] == 'E')
+ {
+ for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
+ if (uses_hard_regs_p (&XVECEXP (*loc, i, j), set))
+ return true;
+ }
+ }
+ return false;
+}
+
/* Major function to choose the current insn alternative and what
operands should be reload and how. If ONLY_ALTERNATIVE is not
negative we should consider only this alternative. Return false if
@@ -1269,18 +1335,20 @@
three times here since we want the disparaging caused by a bad
register class to only count 1/3 as much. */
int reject;
- /* The number of elements in the following two arrays. */
- int curr_early_clobbered_regs_num;
+ /* The number of elements in the following array. */
+ int early_clobbered_regs_num;
/* Numbers of operands which are early clobber registers. */
- int curr_early_clobbered_nops[MAX_RECOG_OPERANDS];
- /* Biggest of mode of the early clobbered registers. */
- enum machine_mode curr_early_clobbered_modes[MAX_RECOG_OPERANDS];
- enum reg_class curr_alternative[MAX_RECOG_OPERANDS];
- HARD_REG_SET curr_alternative_set[MAX_RECOG_OPERANDS];
- bool curr_alternative_match_win[MAX_RECOG_OPERANDS];
- bool curr_alternative_win[MAX_RECOG_OPERANDS];
- bool curr_alternative_offmemok[MAX_RECOG_OPERANDS];
- int curr_alternative_matches[MAX_RECOG_OPERANDS];
+ int early_clobbered_nops[MAX_RECOG_OPERANDS];
+ enum reg_class curr_alt[MAX_RECOG_OPERANDS];
+ HARD_REG_SET curr_alt_set[MAX_RECOG_OPERANDS];
+ bool curr_alt_match_win[MAX_RECOG_OPERANDS];
+ bool curr_alt_win[MAX_RECOG_OPERANDS];
+ bool curr_alt_offmemok[MAX_RECOG_OPERANDS];
+ int curr_alt_matches[MAX_RECOG_OPERANDS];
+ /* The number of elements in the following array. */
+ int curr_alt_dont_inherit_ops_num;
+ /* Numbers of operands whose reload pseudos should not be inherited. */
+ int curr_alt_dont_inherit_ops[MAX_RECOG_OPERANDS];
rtx op;
rtx no_subreg_operand[MAX_RECOG_OPERANDS], operand_reg[MAX_RECOG_OPERANDS];
int hard_regno[MAX_RECOG_OPERANDS];
@@ -1334,7 +1402,7 @@
for (nop = 0; nop < n_operands; nop++)
reject += (curr_static_id
->operand_alternative[nalt * n_operands + nop].reject);
- curr_early_clobbered_regs_num = 0;
+ early_clobbered_regs_num = 0;
for (nop = 0; nop < n_operands; nop++)
{
@@ -1362,12 +1430,12 @@
if (curr_static_id->operand_alternative[opalt_num].anything_ok)
{
/* Fast track for no constraints at all. */
- curr_alternative[nop] = NO_REGS;
- CLEAR_HARD_REG_SET (curr_alternative_set[nop]);
- curr_alternative_win[nop] = true;
- curr_alternative_match_win[nop] = false;
- curr_alternative_offmemok[nop] = false;
- curr_alternative_matches[nop] = -1;
+ curr_alt[nop] = NO_REGS;
+ CLEAR_HARD_REG_SET (curr_alt_set[nop]);
+ curr_alt_win[nop] = true;
+ curr_alt_match_win[nop] = false;
+ curr_alt_offmemok[nop] = false;
+ curr_alt_matches[nop] = -1;
continue;
}
@@ -1436,6 +1504,7 @@
case '5': case '6': case '7': case '8': case '9':
{
int m_hregno, m_offset;
+ bool match_p;
m = strtoul (p, &end, 10);
p = end;
@@ -1454,20 +1523,37 @@
operands win. As a result, this alternative may
be rejected when it is actually desirable.) */
/* If it conflicts with others. */
+ match_p = false;
if (operands_match_p (*curr_id->operand_loc[nop],
*curr_id->operand_loc[m], m_hregno))
{
+ int i;
+
+ for (i = 0; i < early_clobbered_regs_num; i++)
+ if (early_clobbered_nops[i] == m)
+ break;
+ /* We should reject matching of an early clobber
+ operand if the matching operand is not dying
+ in the insn. */
+ if (i >= early_clobbered_regs_num
+ || operand_reg[nop] == NULL_RTX
+ || (find_regno_note (curr_insn, REG_DEAD,
+ REGNO (operand_reg[nop]))
+ != NULL_RTX))
+ match_p = true;
+ }
+ if (match_p)
+ {
/* If we are matching a non-offsettable address
where an offsettable address was expected,
then we must reject this combination, because
we can't reload it. */
- if (curr_alternative_offmemok[m]
+ if (curr_alt_offmemok[m]
&& MEM_P (*curr_id->operand_loc[m])
- && curr_alternative[m] == NO_REGS
- && ! curr_alternative_win[m])
+ && curr_alt[m] == NO_REGS && ! curr_alt_win[m])
continue;
- did_match = curr_alternative_win[m];
+ did_match = curr_alt_win[m];
}
else
{
@@ -1476,11 +1562,11 @@
match as a loser, if it wasn't already and it
wasn't matched to a register constraint (e.g
it might be matched by memory). */
- if (curr_alternative_win[m]
+ if (curr_alt_win[m]
&& (operand_reg[m] == NULL_RTX || hard_regno[m] < 0))
losers++;
invalidate_m = m;
- if (curr_alternative[m] == NO_REGS)
+ if (curr_alt[m] == NO_REGS)
continue;
/* We prefer no matching alternatives because it
@@ -1495,9 +1581,8 @@
are supposed to match can be fixed with
reloads. */
badop = false;
- this_alternative = curr_alternative[m];
- COPY_HARD_REG_SET (this_alternative_set,
- curr_alternative_set[m]);
+ this_alternative = curr_alt[m];
+ COPY_HARD_REG_SET (this_alternative_set, curr_alt_set[m]);
/* If we have to reload this operand and some
previous operand also had to match the same thing
@@ -1505,8 +1590,7 @@
So reject this alternative. */
if (! did_match)
for (i = 0; i < nop; i++)
- if (curr_alternative_matches[i]
- == this_alternative_matches)
+ if (curr_alt_matches[i] == this_alternative_matches)
badop = true;
break;
@@ -1766,7 +1850,7 @@
not need to generate a reload insn for this
operand. */
if (this_alternative_matches < 0
- || curr_alternative_win[this_alternative_matches]
+ || curr_alt_win[this_alternative_matches]
|| ! REG_P (op)
|| find_regno_note (curr_insn, REG_DEAD,
REGNO (op)) == NULL_RTX
@@ -1878,22 +1962,83 @@
if ((best_losers == 0 || losers != 0) && best_overall < overall)
goto fail;
- curr_alternative[nop] = this_alternative;
- COPY_HARD_REG_SET (curr_alternative_set[nop], this_alternative_set);
- curr_alternative_win[nop] = this_alternative_win;
- curr_alternative_match_win[nop] = this_alternative_match_win;
- curr_alternative_offmemok[nop] = this_alternative_offmemok;
- curr_alternative_matches[nop] = this_alternative_matches;
+ curr_alt[nop] = this_alternative;
+ COPY_HARD_REG_SET (curr_alt_set[nop], this_alternative_set);
+ curr_alt_win[nop] = this_alternative_win;
+ curr_alt_match_win[nop] = this_alternative_match_win;
+ curr_alt_offmemok[nop] = this_alternative_offmemok;
+ curr_alt_matches[nop] = this_alternative_matches;
if (invalidate_m >= 0 && ! this_alternative_win)
- curr_alternative_win[invalidate_m] = false;
+ curr_alt_win[invalidate_m] = false;
if (early_clobber_p && operand_reg[nop] != NULL_RTX)
+ early_clobbered_nops[early_clobbered_regs_num++] = nop;
+ }
+ ok_p = true;
+ curr_alt_dont_inherit_ops_num = 0;
+ for (nop = 0; nop < early_clobbered_regs_num; nop++)
+ {
+ int i, j, clobbered_hard_regno;
+ HARD_REG_SET temp_set;
+
+ i = early_clobbered_nops[nop];
+ if ((! curr_alt_win[i] && ! curr_alt_match_win[i])
+ || hard_regno[i] < 0)
+ continue;
+ clobbered_hard_regno = hard_regno[i];
+ CLEAR_HARD_REG_SET (temp_set);
+ for (j = hard_regno_nregs[clobbered_hard_regno][biggest_mode[i]] - 1;
+ j >= 0;
+ j--)
+ SET_HARD_REG_BIT (temp_set, clobbered_hard_regno + j);
+ for (j = 0; j < n_operands; j++)
+ if (j == i
+ /* We don't want process insides of match_operator and
+ match_parallel because otherwise we would process
+ their operands once again generating a wrong
+ code. */
+ || curr_static_id->operand[j].is_operator)
+ continue;
+ else if (curr_alt_matches[j] == i && curr_alt_match_win[j])
+ {
+ /* This is a trick. Such operands don't conflict and
+ don't need a reload. But it is hard to transfer
+ this information to the assignment pass which
+ spills one operand without this info. We avoid the
+ conflict by forcing to use the same pseudo for the
+ operands hoping that the pseudo gets the same hard
+ regno as the operands and the reloads are gone. */
+ curr_alt_win[i] = false;
+ curr_alt_match_win[j] = false;
+ continue;
+ }
+ else if (curr_alt_matches[i] == j && curr_alt_match_win[i])
+ {
+ /* See the comment for the previous case. */
+ curr_alt_win[j] = false;
+ curr_alt_match_win[i] = false;
+ continue;
+ }
+ else if (uses_hard_regs_p (curr_id->operand_loc[j], temp_set))
+ break;
+ if (j >= n_operands)
+ continue;
+ /* We need to reload early clobbered register. */
+ for (j = 0; j < n_operands; j++)
+ if (curr_alt_matches[j] == i)
+ curr_alt_match_win[j] = false;
+ if (! curr_alt_match_win[i])
+ curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++] = i;
+ else
{
- curr_early_clobbered_nops[curr_early_clobbered_regs_num] = nop;
- curr_early_clobbered_modes[curr_early_clobbered_regs_num++]
- = biggest_mode[nop];
+ /* Remember pseudos used for match reloads are never inherited.
*/
+ gcc_assert (curr_alt_matches[i] >= 0);
+ curr_alt_win[curr_alt_matches[i]] = false;
}
+ curr_alt_win[i] = curr_alt_match_win[i] = false;
+ losers++;
+ overall += 6;
}
small_class_operands_num = 0;
for (nop = 0; nop < n_operands; nop++)
@@ -1901,7 +2046,7 @@
it needs less reloading than the others checked so far,
record it as the chosen goal for reloading. */
small_class_operands_num
- += SMALL_REGISTER_CLASS_P (curr_alternative[nop]) ? 1 : 0;
+ += SMALL_REGISTER_CLASS_P (curr_alt[nop]) ? 1 : 0;
if ((best_losers != 0 && losers == 0)
|| (((best_losers == 0 && losers == 0)
@@ -1922,24 +2067,22 @@
{
for (nop = 0; nop < n_operands; nop++)
{
- goal_alternative_win[nop] = curr_alternative_win[nop];
- goal_alternative_match_win[nop]
- = curr_alternative_match_win[nop];
- goal_alternative_matches[nop] = curr_alternative_matches[nop];
- goal_alternative[nop] = curr_alternative[nop];
- goal_alternative_offmemok[nop] = curr_alternative_offmemok[nop];
- goal_early_clobbered_nops[nop] = curr_early_clobbered_nops[nop];
- goal_early_clobbered_modes[nop] = curr_early_clobbered_modes[nop];
+ goal_alt_win[nop] = curr_alt_win[nop];
+ goal_alt_match_win[nop] = curr_alt_match_win[nop];
+ goal_alt_matches[nop] = curr_alt_matches[nop];
+ goal_alt[nop] = curr_alt[nop];
+ goal_alt_offmemok[nop] = curr_alt_offmemok[nop];
}
- goal_early_clobbered_nops_num = curr_early_clobbered_regs_num;
- goal_alternative_swapped = curr_swapped;
+ goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num;
+ for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++)
+ goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop];
+ goal_alt_swapped = curr_swapped;
best_overall = overall;
best_losers = losers;
best_small_class_operands_num = small_class_operands_num;
best_reload_sum = reload_sum;
- goal_alternative_number = nalt;
+ goal_alt_number = nalt;
}
- ok_p = true;
if (losers == 0)
/* Everything is satisfied. Do not process alternatives
anymore. */
@@ -2375,216 +2518,6 @@
return result;
}
-/* Number of elements in the following array. */
-static int early_clobber_reload_regs_num;
-
-/* Info about registers which we already reloaded because of conflict
- with early clobber. */
-static struct
-{
- /* Regno of already reloaded register because of conflict with early
- clobber. */
- int regno;
- /* New register used for the reload. */
- rtx new_reg;
-} early_clobber_reload_regs[MAX_RECOG_OPERANDS];
-
-/* The function returns a new register of class RCLASS which should be
- used for reload input register X because of conflict with an early
- clobbered register. If such new register are being created, emit
- the reload insns and put them to INSERT sequence. */
-static rtx
-make_early_clobber_input_reload_reg (rtx x, enum reg_class rclass,
- rtx *insert)
-{
- int i, regno;
- rtx new_reg;
-
- gcc_assert (REG_P (x));
- regno = REGNO (x);
- for (i = 0; i < early_clobber_reload_regs_num; i++)
- if (early_clobber_reload_regs[i].regno == regno
- /* It is not worth to check class subsets or to use class
- intersects because such cases are extremely rare. */
- && (rclass
- == lra_get_allocno_class (REGNO
(early_clobber_reload_regs[i].new_reg))))
- return early_clobber_reload_regs[i].new_reg;
- if (get_reload_reg (OP_IN, VOIDmode, x, rclass, "early clobbered", &new_reg))
- {
- push_to_sequence (*insert);
- lra_emit_move (new_reg, x);
- *insert = get_insns ();
- end_sequence ();
- }
- gcc_assert (early_clobber_reload_regs_num < MAX_RECOG_OPERANDS);
- early_clobber_reload_regs[early_clobber_reload_regs_num].regno = regno;
- early_clobber_reload_regs[early_clobber_reload_regs_num++].new_reg
- = new_reg;
- return new_reg;
-}
-
-/* Replace registers conflicting with early clobbered registers in
- *LOC which is inside the operand with number NOP. The substitution
- register should have class RCLASS and the reload insns (if it is
- not created yet) should be put into sequence *BEFORE. *LOC is an
- insn input if IN_P. If the clobbered register is a hard register,
- replace it by a new pseudo whose class should be RCLASS and the
- reload insns should be put into sequence *BEFORE. If a replacement
- is done, return TRUE. */
-static bool
-search_and_replace_reg (int nop, rtx *loc, enum reg_class rclass,
- rtx *before, rtx *after, bool in_p)
-{
- int i, j, clobber_nop, x_hard_regno, clobbered_hard_regno;
- bool res;
- enum machine_mode mode;
- rtx x, *clobbered_reg_loc, new_reg;
- const char *fmt;
- enum rtx_code code;
- HARD_REG_SET temp_set;
-
- if (*loc == NULL_RTX)
- return false;
- x = *loc;
- code = GET_CODE (x);
- mode = GET_MODE (x);
- if (code == SUBREG)
- {
- loc = &SUBREG_REG (x);
- x = SUBREG_REG (x);
- code = GET_CODE (x);
- if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
- mode = GET_MODE (x);
- }
-
- res = false;
- if (REG_P (x))
- {
- if (! in_p)
- return false;
- for (i = 0; i < goal_early_clobbered_nops_num; i++)
- {
- clobber_nop = goal_early_clobbered_nops[i];
- if (goal_alternative_matches[nop] == clobber_nop
- || goal_alternative_matches[clobber_nop] == nop)
- continue;
- clobbered_reg_loc = curr_id->operand_loc[clobber_nop];
- if (GET_CODE (*clobbered_reg_loc) == SUBREG)
- clobbered_reg_loc = &SUBREG_REG (*clobbered_reg_loc);
- x_hard_regno = REGNO (x);
- if (x_hard_regno >= FIRST_PSEUDO_REGISTER)
- x_hard_regno = reg_renumber[x_hard_regno];
- clobbered_hard_regno = REGNO (*clobbered_reg_loc);
- if (clobbered_hard_regno >= FIRST_PSEUDO_REGISTER)
- clobbered_hard_regno = reg_renumber[clobbered_hard_regno];
- CLEAR_HARD_REG_SET (temp_set);
- if (clobbered_hard_regno >= 0)
- {
- for (j = (hard_regno_nregs[clobbered_hard_regno]
- [goal_early_clobbered_modes[i]]) - 1;
- j >= 0;
- j--)
- SET_HARD_REG_BIT (temp_set, clobbered_hard_regno + j);
- }
- /* Examples of conflicts: 1) early clobbered pseudo which is
- also an address register in a memory; 2) early clobbered
- pseudo which got the same hard register as an input
- operand (it might be a hard register itself). ??? Should
- we fix it in IRA. */
- if (x != *clobbered_reg_loc
- && (x_hard_regno == -1
- || clobbered_hard_regno == -1
- || ! lra_hard_reg_set_intersection_p (x_hard_regno, mode,
- temp_set)))
- continue;
- if (REGNO (*clobbered_reg_loc) >= FIRST_PSEUDO_REGISTER)
- {
- new_reg
- = make_early_clobber_input_reload_reg (x, rclass, before);
- *loc = new_reg;
- }
- else
- {
- /* In case of conflict with another input, the following
- code is not executed again because a new register has
- no hard register yet. */
- gcc_assert (goal_alternative[clobber_nop] != NO_REGS);
- new_reg = lra_create_new_reg (VOIDmode, *clobbered_reg_loc,
- goal_alternative[clobber_nop],
- "early clobbered");
- push_to_sequence (*after);
- lra_emit_move (*clobbered_reg_loc, new_reg);
- *after = get_insns ();
- end_sequence ();
- *clobbered_reg_loc = new_reg;
- }
- bitmap_set_bit (&lra_dont_inherit_pseudos, REGNO (new_reg));
- res = true;
- }
- return res;
- }
- if (MEM_P (x))
- {
- struct address ad;
- enum machine_mode mode = GET_MODE (x);
- rtx *addr_loc = &XEXP (x, 0);
-
- extract_address_regs (mode, addr_loc, MEM, &ad);
- if (ad.base_reg_loc != NULL)
- res = search_and_replace_reg (nop, ad.base_reg_loc,
- base_reg_class (mode,
- ad.base_outer_code,
- ad.index_code),
- before, after, true);
- if (ad.index_reg_loc != NULL)
- res = (search_and_replace_reg (nop, ad.index_reg_loc,
- INDEX_REG_CLASS, before, after, true)
- || res);
- }
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- res = search_and_replace_reg (nop, &XEXP (x, i),
- rclass, before, after, in_p) || res;
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
- res = search_and_replace_reg (nop, &XVECEXP (*loc, i, j),
- rclass, before, after, in_p) || res;
- }
- }
- return res;
-}
-
-/* Make reload insn and put them into sequence *BEFORE or *AFTER to
- resolve conflicts of inputs with early clobbered registers.
- Unfortunately IRA does not avoid such conflict creation, e.g. when
- early clobbered pseudo also present in a memory as an address
- register.
-
- ??? Should we fix such conflicts in IRA (pro: we can remove this
- code here, contra: we can not do it effectively in IRA because we
- don't know yet there what insn alternative will be used). */
-static void
-create_early_clobber_reloads (rtx *before, rtx *after)
-{
- int i;
-
- if (goal_early_clobbered_nops_num == 0)
- return;
- early_clobber_reload_regs_num = 0;
- for (i = 0; i < curr_static_id->n_operands; i++)
- /* We don't want process insides of match_operator and
- match_parallel because otherwise we would process their
- operands once again generating a wrong code. */
- if (! curr_static_id->operand[i].is_operator
- && search_and_replace_reg (i, curr_id->operand_loc[i],
- goal_alternative[i], before, after,
- curr_static_id->operand[i].type == OP_IN))
- lra_update_dups (curr_id, i, -1);
-}
-
/* Main entry point of this file: search the body of the current insn
to choose the best alternative. It is mimicking insn alternative
cost calculation model of former reload pass. That is because
@@ -2601,7 +2534,7 @@
int n_alternatives;
int n_dups;
int commutative;
- int goal_alternative_matched[MAX_RECOG_OPERANDS];
+ int goal_alt_matched[MAX_RECOG_OPERANDS];
rtx before, after;
bool alt_p = false;
/* Flag that the insn has been changed through a transformation. */
@@ -2610,7 +2543,7 @@
int reused_alternative_num;
no_input_reloads_p = no_output_reloads_p = false;
- goal_alternative_number = 0;
+ goal_alt_number = 0;
if (check_and_process_move (&change_p))
return change_p;
@@ -2641,8 +2574,8 @@
for (i = 0; i < n_operands; i++)
{
- goal_alternative_matched[i] = -1;
- goal_alternative_matches[i] = -1;
+ goal_alt_matched[i] = -1;
+ goal_alt_matches[i] = -1;
}
commutative = curr_static_id->commutative;
@@ -2655,7 +2588,7 @@
best_small_class_operands_num = best_reload_sum = 0;
curr_swapped = false;
- goal_alternative_swapped = false;
+ goal_alt_swapped = false;
/* Make equivalence substitution and memory subreg elimination
before address processing because an address legitimacy can
@@ -2747,9 +2680,9 @@
}
}
- /* The operands don't meet the constraints. goal_alternative
- describes the alternative that we could reach by reloading the
- fewest operands. Reload so as to fit it. */
+ /* The operands don't meet the constraints. goal_alt describes the
+ alternative that we could reach by reloading the fewest operands.
+ Reload so as to fit it. */
if (! alt_p)
{
@@ -2768,7 +2701,7 @@
them. Update the operand numbers of any reloads already
pushed. */
- if (goal_alternative_swapped)
+ if (goal_alt_swapped)
{
rtx tem;
rtx x;
@@ -2800,19 +2733,18 @@
change_p = true;
}
- lra_set_used_insn_alternative (curr_insn,
- goal_alternative_number);
+ lra_set_used_insn_alternative (curr_insn, goal_alt_number);
if (lra_dump_file != NULL)
{
const char *p;
fprintf (lra_dump_file, " Choosing alt %d in insn %u:",
- goal_alternative_number, INSN_UID (curr_insn));
+ goal_alt_number, INSN_UID (curr_insn));
for (i = 0; i < n_operands; i++)
{
p = (curr_static_id->operand_alternative
- [goal_alternative_number * n_operands + i].constraint);
+ [goal_alt_number * n_operands + i].constraint);
if (*p == '\0')
continue;
fprintf (lra_dump_file, " (%d) ", i);
@@ -2823,21 +2755,21 @@
}
/* Right now, for any pair of operands I and J that are required to
- match, with I < J, goal_alternative_matches[J] is I. Set up
- goal_alternative_matched as the inverse function:
- goal_alternative_matched[I] = J. */
+ match, with I < J, goal_alt_matches[J] is I. Set up
+ goal_alt_matched as the inverse function: goal_alt_matched[I] =
+ J. */
for (i = 0; i < n_operands; i++)
- if (goal_alternative_matches[i] >= 0)
- goal_alternative_matched[goal_alternative_matches[i]] = i;
+ if (goal_alt_matches[i] >= 0)
+ goal_alt_matched[goal_alt_matches[i]] = i;
for (i = 0; i < n_operands; i++)
- goal_alternative_win[i] |= goal_alternative_match_win[i];
+ goal_alt_win[i] |= goal_alt_match_win[i];
/* Any constants that aren't allowed and can't be reloaded into
registers are here changed into memory references. */
for (i = 0; i < n_operands; i++)
- if (goal_alternative_win[i])
+ if (goal_alt_win[i])
{
int regno;
enum reg_class new_class;
@@ -2848,7 +2780,7 @@
if (REG_P (reg) && (regno = REGNO (reg)) >= FIRST_PSEUDO_REGISTER)
{
- bool ok_p = in_class_p (regno, goal_alternative[i], &new_class);
+ bool ok_p = in_class_p (regno, goal_alt[i], &new_class);
if (new_class != NO_REGS && get_reg_class (regno) != new_class)
{
@@ -2882,7 +2814,7 @@
if (CONST_POOL_OK_P (mode, op)
&& ((targetm.preferred_reload_class
- (op, (enum reg_class) goal_alternative[i]) == NO_REGS)
+ (op, (enum reg_class) goal_alt[i]) == NO_REGS)
|| no_input_reloads_p)
&& mode != VOIDmode)
{
@@ -2905,9 +2837,8 @@
if (plus != NULL_RTX || subreg != NULL_RTX)
continue;
/* Skip alternatives before the one requested. */
- constraint
- = (curr_static_id->operand_alternative
- [goal_alternative_number * n_operands + i].constraint);
+ constraint = (curr_static_id->operand_alternative
+ [goal_alt_number * n_operands + i].constraint);
for (;
(c = *constraint) && c != ',' && c != '#';
constraint += CONSTRAINT_LEN (c, constraint))
@@ -2923,7 +2854,7 @@
if (c == '\0' || c == ',' || c == '#')
continue;
- goal_alternative_win[i] = true;
+ goal_alt_win[i] = true;
}
}
@@ -2932,9 +2863,9 @@
rtx old, new_reg;
rtx op = *curr_id->operand_loc[i];
- if (goal_alternative_win[i])
+ if (goal_alt_win[i])
{
- if (goal_alternative[i] == NO_REGS
+ if (goal_alt[i] == NO_REGS
&& REG_P (op)
&& lra_former_scratch_operand_p (curr_insn, i))
change_class (REGNO (op), NO_REGS, " Change", true);
@@ -2942,16 +2873,14 @@
}
/* Operands that match previous ones have already been handled. */
- if (goal_alternative_matches[i] >= 0)
+ if (goal_alt_matches[i] >= 0)
continue;
/* We should not have an operand with a nonoffsettable address
appearing where an offsettable address will do. It also may
be a case when the address should be special in other words
not a general one (e.g. it needs no index reg). */
- if (goal_alternative_matched[i] == -1
- && goal_alternative_offmemok[i]
- && MEM_P (op))
+ if (goal_alt_matched[i] == -1 && goal_alt_offmemok[i] && MEM_P (op))
{
enum reg_class rclass;
rtx *loc = &XEXP (op, 0);
@@ -2973,11 +2902,11 @@
*loc = new_reg;
lra_update_dups (curr_id, i, -1);
}
- else if (goal_alternative_matched[i] == -1)
+ else if (goal_alt_matched[i] == -1)
{
enum machine_mode mode;
rtx reg, *loc;
- int hard_regno, byte;
+ int j, hard_regno, byte;
enum op_type type = curr_static_id->operand[i].type;
loc = curr_id->operand_loc[i];
@@ -2997,9 +2926,9 @@
&& (simplify_subreg_regno
(hard_regno,
GET_MODE (reg), byte, mode) < 0)
- && (goal_alternative[i] == NO_REGS
+ && (goal_alt[i] == NO_REGS
|| (simplify_subreg_regno
- (ira_class_hard_regs[goal_alternative[i]][0],
+ (ira_class_hard_regs[goal_alt[i]][0],
GET_MODE (reg), byte, mode) >= 0)))))
{
loc = &SUBREG_REG (*loc);
@@ -3007,7 +2936,7 @@
}
}
old = *loc;
- if (get_reload_reg (type, mode, old, goal_alternative[i], "",
&new_reg)
+ if (get_reload_reg (type, mode, old, goal_alt[i], "", &new_reg)
&& type != OP_OUT)
{
push_to_sequence (before);
@@ -3027,18 +2956,21 @@
}
*loc = new_reg;
}
+ for (j = 0; j < goal_alt_dont_inherit_ops_num; j++)
+ if (goal_alt_dont_inherit_ops[j] == i)
+ {
+ bitmap_set_bit (&lra_dont_inherit_pseudos, REGNO (new_reg));
+ break;
+ }
lra_update_dups (curr_id, i, -1);
}
else if (curr_static_id->operand[i].type == OP_IN
- && (curr_static_id
- ->operand[goal_alternative_matched[i]].type == OP_OUT))
- match_reload (goal_alternative_matched[i], i,
- goal_alternative[i], &before, &after);
+ && curr_static_id->operand[goal_alt_matched[i]].type == OP_OUT)
+ match_reload (goal_alt_matched[i], i,
+ goal_alt[i], &before, &after);
else if (curr_static_id->operand[i].type == OP_OUT
- && (curr_static_id
- ->operand[goal_alternative_matched[i]].type == OP_IN))
- match_reload (i, goal_alternative_matched[i],
- goal_alternative[i], &before, &after);
+ && curr_static_id->operand[goal_alt_matched[i]].type == OP_IN)
+ match_reload (i, goal_alt_matched[i], goal_alt[i], &before, &after);
else
{
gcc_assert (INSN_CODE (curr_insn) < 0);
@@ -3049,7 +2981,6 @@
return false;
}
}
- create_early_clobber_reloads (&before, &after);
if (before != NULL_RTX || after != NULL_RTX || max_regno_before !=
max_reg_num ())
change_p = true;
if (change_p)