aboutsummaryrefslogtreecommitdiff
path: root/gcc/ira.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ira.c')
-rw-r--r--gcc/ira.c144
1 files changed, 121 insertions, 23 deletions
diff --git a/gcc/ira.c b/gcc/ira.c
index fc77131..866fb98 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1871,6 +1871,7 @@ ira_setup_alts (rtx_insn *insn)
goto op_success;
case CT_MEMORY:
+ case CT_RELAXED_MEMORY:
mem = op;
/* Fall through. */
case CT_SPECIAL_MEMORY:
@@ -1921,9 +1922,25 @@ ira_setup_alts (rtx_insn *insn)
/* Return the number of the output non-early clobber operand which
should be the same in any case as operand with number OP_NUM (or
negative value if there is no such operand). ALTS is the mask
- of alternatives that we should consider. */
+ of alternatives that we should consider. SINGLE_INPUT_OP_HAS_CSTR_P
+ should be set in this function, it indicates whether there is only
+ a single input operand which has the matching constraint on the
+ output operand at the position specified in return value. If the
+ pattern allows any one of several input operands holds the matching
+ constraint, it's set as false, one typical case is destructive FMA
+ instruction on target rs6000. Note that for a non-NO_REG preferred
+ register class with no free register move copy, if the parameter
+ PARAM_IRA_CONSIDER_DUP_IN_ALL_ALTS is set to one, this function
+ will check all available alternatives for matching constraints,
+ even if it has found or will find one alternative with non-NO_REG
+ regclass, it can respect more cases with matching constraints. If
+ PARAM_IRA_CONSIDER_DUP_IN_ALL_ALTS is set to zero,
+ SINGLE_INPUT_OP_HAS_CSTR_P is always true, it will stop to find
+ matching constraint relationship once it hits some alternative with
+ some non-NO_REG regclass. */
int
-ira_get_dup_out_num (int op_num, alternative_mask alts)
+ira_get_dup_out_num (int op_num, alternative_mask alts,
+ bool &single_input_op_has_cstr_p)
{
int curr_alt, c, original;
bool ignore_p, use_commut_op_p;
@@ -1936,10 +1953,42 @@ ira_get_dup_out_num (int op_num, alternative_mask alts)
return -1;
str = recog_data.constraints[op_num];
use_commut_op_p = false;
+ single_input_op_has_cstr_p = true;
+
+ rtx op = recog_data.operand[op_num];
+ int op_regno = reg_or_subregno (op);
+ enum reg_class op_pref_cl = reg_preferred_class (op_regno);
+ machine_mode op_mode = GET_MODE (op);
+
+ ira_init_register_move_cost_if_necessary (op_mode);
+ /* If the preferred regclass isn't NO_REG, continue to find the matching
+ constraint in all available alternatives with preferred regclass, even
+ if we have found or will find one alternative whose constraint stands
+ for a REG (non-NO_REG) regclass. Note that it would be fine not to
+ respect matching constraint if the register copy is free, so exclude
+ it. */
+ bool respect_dup_despite_reg_cstr
+ = param_ira_consider_dup_in_all_alts
+ && op_pref_cl != NO_REGS
+ && ira_register_move_cost[op_mode][op_pref_cl][op_pref_cl] > 0;
+
+ /* Record the alternative whose constraint uses the same regclass as the
+ preferred regclass, later if we find one matching constraint for this
+ operand with preferred reclass, we will visit these recorded
+ alternatives to check whether if there is one alternative in which no
+ any INPUT operands have one matching constraint same as our candidate.
+ If yes, it means there is one alternative which is perfectly fine
+ without satisfying this matching constraint. If no, it means in any
+ alternatives there is one other INPUT operand holding this matching
+ constraint, it's fine to respect this matching constraint and further
+ create this constraint copy since it would become harmless once some
+ other takes preference and it's interfered. */
+ alternative_mask pref_cl_alts;
+
for (;;)
{
- rtx op = recog_data.operand[op_num];
-
+ pref_cl_alts = 0;
+
for (curr_alt = 0, ignore_p = !TEST_BIT (alts, curr_alt),
original = -1;;)
{
@@ -1962,9 +2011,25 @@ ira_get_dup_out_num (int op_num, alternative_mask alts)
{
enum constraint_num cn = lookup_constraint (str);
enum reg_class cl = reg_class_for_constraint (cn);
- if (cl != NO_REGS
- && !targetm.class_likely_spilled_p (cl))
- goto fail;
+ if (cl != NO_REGS && !targetm.class_likely_spilled_p (cl))
+ {
+ if (respect_dup_despite_reg_cstr)
+ {
+ /* If it's free to move from one preferred class to
+ the one without matching constraint, it doesn't
+ have to respect this constraint with costs. */
+ if (cl != op_pref_cl
+ && (ira_reg_class_intersect[cl][op_pref_cl]
+ != NO_REGS)
+ && (ira_may_move_in_cost[op_mode][op_pref_cl][cl]
+ == 0))
+ goto fail;
+ else if (cl == op_pref_cl)
+ pref_cl_alts |= ALTERNATIVE_BIT (curr_alt);
+ }
+ else
+ goto fail;
+ }
if (constraint_satisfied_p (op, cn))
goto fail;
break;
@@ -1978,7 +2043,21 @@ ira_get_dup_out_num (int op_num, alternative_mask alts)
str = end;
if (original != -1 && original != n)
goto fail;
- original = n;
+ gcc_assert (n < recog_data.n_operands);
+ if (respect_dup_despite_reg_cstr)
+ {
+ const operand_alternative *op_alt
+ = &recog_op_alt[curr_alt * recog_data.n_operands];
+ /* Only respect the one with preferred rclass, without
+ respect_dup_despite_reg_cstr it's possible to get
+ one whose regclass isn't preferred first before,
+ but it would fail since there should be other
+ alternatives with preferred regclass. */
+ if (op_alt[n].cl == op_pref_cl)
+ original = n;
+ }
+ else
+ original = n;
continue;
}
}
@@ -1987,7 +2066,39 @@ ira_get_dup_out_num (int op_num, alternative_mask alts)
if (original == -1)
goto fail;
if (recog_data.operand_type[original] == OP_OUT)
- return original;
+ {
+ if (pref_cl_alts == 0)
+ return original;
+ /* Visit these recorded alternatives to check whether
+ there is one alternative in which no any INPUT operands
+ have one matching constraint same as our candidate.
+ Give up this candidate if so. */
+ int nop, nalt;
+ for (nalt = 0; nalt < recog_data.n_alternatives; nalt++)
+ {
+ if (!TEST_BIT (pref_cl_alts, nalt))
+ continue;
+ const operand_alternative *op_alt
+ = &recog_op_alt[nalt * recog_data.n_operands];
+ bool dup_in_other = false;
+ for (nop = 0; nop < recog_data.n_operands; nop++)
+ {
+ if (recog_data.operand_type[nop] != OP_IN)
+ continue;
+ if (nop == op_num)
+ continue;
+ if (op_alt[nop].matches == original)
+ {
+ dup_in_other = true;
+ break;
+ }
+ }
+ if (!dup_in_other)
+ return -1;
+ }
+ single_input_op_has_cstr_p = false;
+ return original;
+ }
fail:
if (use_commut_op_p)
break;
@@ -3084,7 +3195,6 @@ equiv_init_movable_p (rtx x, int regno)
case SET:
return equiv_init_movable_p (SET_SRC (x), regno);
- case CC0:
case CLOBBER:
return 0;
@@ -3169,7 +3279,6 @@ memref_referenced_p (rtx memref, rtx x, bool read_p)
case SYMBOL_REF:
CASE_CONST_ANY:
case PC:
- case CC0:
case HIGH:
case LO_SUM:
return false;
@@ -4447,9 +4556,6 @@ rtx_moveable_p (rtx *loc, enum op_type type)
case PC:
return type == OP_IN;
- case CC0:
- return false;
-
case REG:
if (x == frame_pointer_rtx)
return true;
@@ -4740,13 +4846,6 @@ find_moveable_pseudos (void)
? " (no unique first use)" : "");
continue;
}
- if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (closest_use)))
- {
- if (dump_file)
- fprintf (dump_file, "Reg %d: closest user uses cc0\n",
- regno);
- continue;
- }
bitmap_set_bit (interesting, regno);
/* If we get here, we know closest_use is a non-NULL insn
@@ -4821,8 +4920,7 @@ find_moveable_pseudos (void)
if (!bitmap_bit_p (def_bb_transp, regno))
{
if (bitmap_bit_p (def_bb_moveable, regno)
- && !control_flow_insn_p (use_insn)
- && (!HAVE_cc0 || !sets_cc0_p (use_insn)))
+ && !control_flow_insn_p (use_insn))
{
if (modified_between_p (DF_REF_REG (use), def_insn, use_insn))
{