@@ -498,6 +498,7 @@ ira_create_allocno (int regno, bool cap_p,
ALLOCNO_NREFS (a) = 0;
ALLOCNO_FREQ (a) = 0;
ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P (a) = false;
+ ALLOCNO_SET_REGISTER_FILTERS (a, 0);
ALLOCNO_HARD_REGNO (a) = -1;
ALLOCNO_CALL_FREQ (a) = 0;
ALLOCNO_CALLS_CROSSED_NUM (a) = 0;
@@ -902,6 +903,7 @@ create_cap_allocno (ira_allocno_t a)
ALLOCNO_NREFS (cap) = ALLOCNO_NREFS (a);
ALLOCNO_FREQ (cap) = ALLOCNO_FREQ (a);
ALLOCNO_CALL_FREQ (cap) = ALLOCNO_CALL_FREQ (a);
+ ALLOCNO_SET_REGISTER_FILTERS (cap, ALLOCNO_REGISTER_FILTERS (a));
merge_hard_reg_conflicts (a, cap, false);
@@ -2064,6 +2066,9 @@ propagate_allocno_info (void)
ALLOCNO_BAD_SPILL_P (parent_a) = false;
ALLOCNO_NREFS (parent_a) += ALLOCNO_NREFS (a);
ALLOCNO_FREQ (parent_a) += ALLOCNO_FREQ (a);
+ ALLOCNO_SET_REGISTER_FILTERS (parent_a,
+ ALLOCNO_REGISTER_FILTERS (parent_a)
+ | ALLOCNO_REGISTER_FILTERS (a));
/* If A's allocation can differ from PARENT_A's, we can if necessary
spill PARENT_A on entry to A's loop and restore it afterwards.
@@ -2465,6 +2470,9 @@ propagate_some_info_from_allocno (ira_allocno_t a, ira_allocno_t from_a)
ALLOCNO_CROSSED_CALLS_ABIS (a) |= ALLOCNO_CROSSED_CALLS_ABIS (from_a);
ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a)
|= ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (from_a);
+ ALLOCNO_SET_REGISTER_FILTERS (a,
+ ALLOCNO_REGISTER_FILTERS (from_a)
+ | ALLOCNO_REGISTER_FILTERS (a));
ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (a)
+= ALLOCNO_EXCESS_PRESSURE_POINTS_NUM (from_a);
@@ -2163,6 +2163,9 @@ assign_hard_reg (ira_allocno_t a, bool retry_p)
if (! check_hard_reg_p (a, hard_regno,
conflicting_regs, profitable_hard_regs))
continue;
+ if (NUM_REGISTER_FILTERS
+ && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hard_regno))
+ continue;
cost = costs[i];
full_cost = full_costs[i];
if (!HONOR_REG_ALLOC_ORDER)
@@ -3205,6 +3208,9 @@ improve_allocation (void)
if (! check_hard_reg_p (a, hregno,
conflicting_regs, profitable_hard_regs))
continue;
+ if (NUM_REGISTER_FILTERS
+ && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a), hregno))
+ continue;
ira_assert (ira_class_hard_reg_index[aclass][hregno] == j);
k = allocno_costs == NULL ? 0 : j;
costs[hregno] = (allocno_costs == NULL
@@ -5275,6 +5281,10 @@ fast_allocation (void)
|| (TEST_HARD_REG_BIT
(ira_prohibited_class_mode_regs[aclass][mode], hard_regno)))
continue;
+ if (NUM_REGISTER_FILTERS
+ && !test_register_filters (ALLOCNO_REGISTER_FILTERS (a),
+ hard_regno))
+ continue;
if (costs == NULL)
{
best_hard_regno = hard_regno;
@@ -328,6 +328,13 @@ struct ira_allocno
This is only ever true for non-cap allocnos. */
unsigned int might_conflict_with_parent_p : 1;
+#ifndef NUM_REGISTER_FILTERS
+#error "insn-config.h not included"
+#elif NUM_REGISTER_FILTERS
+ /* The set of register filters applied to the allocno by operand
+ alternatives that accept class ACLASS. */
+ unsigned int register_filters : NUM_REGISTER_FILTERS;
+#endif
/* Accumulated usage references of the allocno. Here and below,
word 'accumulated' means info for given region and all nested
subregions. In this case, 'accumulated' means sum of references
@@ -432,6 +439,13 @@ struct ira_allocno
#define ALLOCNO_FREQ(A) ((A)->freq)
#define ALLOCNO_MIGHT_CONFLICT_WITH_PARENT_P(A) \
((A)->might_conflict_with_parent_p)
+#if NUM_REGISTER_FILTERS
+#define ALLOCNO_REGISTER_FILTERS(A) (A)->register_filters
+#define ALLOCNO_SET_REGISTER_FILTERS(A, X) ((A)->register_filters = (X))
+#else
+#define ALLOCNO_REGISTER_FILTERS(A) 0
+#define ALLOCNO_SET_REGISTER_FILTERS(A, X) ((void) (A), gcc_assert ((X) == 0))
+#endif
#define ALLOCNO_HARD_REGNO(A) ((A)->hard_regno)
#define ALLOCNO_CALL_FREQ(A) ((A)->call_freq)
#define ALLOCNO_CALLS_CROSSED_NUM(A) ((A)->calls_crossed_num)
@@ -1066,6 +1066,66 @@ process_single_reg_class_operands (bool in_p, int freq)
}
}
+/* Go through the operands of the extracted insn looking for operand
+ alternatives that apply a register filter. Record any such filters
+ in the operand's allocno. */
+static void
+process_register_constraint_filters ()
+{
+ for (int opno = 0; opno < recog_data.n_operands; ++opno)
+ {
+ rtx op = recog_data.operand[opno];
+ if (SUBREG_P (op))
+ op = SUBREG_REG (op);
+ if (REG_P (op) && !HARD_REGISTER_P (op))
+ {
+ ira_allocno_t a = ira_curr_regno_allocno_map[REGNO (op)];
+ for (int alt = 0; alt < recog_data.n_alternatives; alt++)
+ {
+ if (!TEST_BIT (preferred_alternatives, alt))
+ continue;
+
+ auto *op_alt = &recog_op_alt[alt * recog_data.n_operands];
+ auto cl = alternative_class (op_alt, opno);
+ /* The two extremes are easy:
+
+ - We should record the filter if CL matches the
+ allocno class.
+
+ - We should ignore the filter if CL and the allocno class
+ are disjoint. We'll either pick a different alternative
+ or reload the operand.
+
+ Things are trickier if the classes overlap. However:
+
+ - If the allocno class includes registers that are not
+ in CL, some choices of hard register will need a reload
+ anyway. It isn't obvious that reloads due to filters
+ are worse than reloads due to regnos being outside CL.
+
+ - Conversely, if the allocno class is a subset of CL,
+ any allocation will satisfy the class requirement.
+ We should try to make sure it satisfies the filter
+ requirement too. This is useful if, for example,
+ an allocno needs to be in "low" registers to satisfy
+ some uses, and its allocno class is therefore those
+ low registers, but the allocno is elsewhere allowed
+ to be in any even-numbered register. Picking an
+ even-numbered low register satisfies both types of use. */
+ if (!ira_class_subset_p[ALLOCNO_CLASS (a)][cl])
+ continue;
+
+ auto filters = alternative_register_filters (op_alt, opno);
+ if (!filters)
+ continue;
+
+ filters |= ALLOCNO_REGISTER_FILTERS (a);
+ ALLOCNO_SET_REGISTER_FILTERS (a, filters);
+ }
+ }
+ }
+}
+
/* Look through the CALL_INSN_FUNCTION_USAGE of a call insn INSN, and see if
we find a SET rtx that we can use to deduce that a register can be cheaply
caller-saved. Return such a register, or NULL_RTX if none is found. */
@@ -1378,6 +1438,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
}
preferred_alternatives = ira_setup_alts (insn);
+ process_register_constraint_filters ();
process_single_reg_class_operands (false, freq);
if (call_p)