This patch makes IRA apply register filters when picking hard registers.
All the new code should be optimised away on targets that don't use
register filters. On targets that do use them, the new register_filters
bitfield is expected to be only a handful of bits.
Information about register filters is recorded in process_bb_node_lives.
The information isn't really related to liveness, but it's a convenient
point because (a) we've already built the allocno structures and
(b) we've already extracted the insn and preprocessed the constraints.
gcc/
* ira-int.h (ira_allocno): Add a register_filters field.
(ALLOCNO_REGISTER_FILTERS): New macro.
(ALLOCNO_SET_REGISTER_FILTERS): Likewise.
* ira-build.cc (ira_create_allocno): Initialize register_filters.
(create_cap_allocno): Propagate register_filters.
(propagate_allocno_info): Likewise.
(propagate_some_info_from_allocno): Likewise.
* ira-lives.cc (process_register_constraint_filters): New function.
(process_bb_node_lives): Use it to record register filter
information.
* ira-color.cc (assign_hard_reg): Check register filters.
(improve_allocation, fast_allocation): Likewise.
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;
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);
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.
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);
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)
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
|| (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;
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
#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)
}
}
+/* 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. */
}
preferred_alternatives = ira_setup_alts (insn);
+ process_register_constraint_filters ();
process_single_reg_class_operands (false, freq);
if (call_p)