aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2023-11-21 15:39:09 +0000
committerRichard Sandiford <richard.sandiford@arm.com>2023-11-21 15:39:09 +0000
commit82651648107993b6ca8cf9bf20ee17215da66473 (patch)
treef04b388bcaf473ef3fcb0f12585a9488c77f3f97
parent09a85191d01e337d84f9c4bc13f3515e8b40e3af (diff)
downloadgcc-82651648107993b6ca8cf9bf20ee17215da66473.zip
gcc-82651648107993b6ca8cf9bf20ee17215da66473.tar.gz
gcc-82651648107993b6ca8cf9bf20ee17215da66473.tar.bz2
recog: Handle register filters
The main (but simplest) part of this patch makes constrain_operands take register filters into account. The rest of the patch adds register filter information to operand_alternative. Generally, if two register constraints have different register filters, it's better if they're in separate alternatives. However, the syntax doesn't enforce that, and we can't assert it due to inline asms. So it's a choice between (a) adding code to enforce consistent filters or (b) dealing with mixes of filters in a conservatively correct way (in the sense of not allowing invalid operands). The latter seems much easier. The patch therefore adds a mask of the filters that apply to at least one constraint in a given operand alternative. A register is OK if it passes all of the filters in the mask. gcc/ * recog.h (operand_alternative): Add a register_filters field. (alternative_register_filters): New function. * recog.cc (preprocess_constraints): Calculate the filters field. (constrain_operands): Check register filters.
-rw-r--r--gcc/recog.cc14
-rw-r--r--gcc/recog.h24
2 files changed, 34 insertions, 4 deletions
diff --git a/gcc/recog.cc b/gcc/recog.cc
index 3bd2d73..eaab79c 100644
--- a/gcc/recog.cc
+++ b/gcc/recog.cc
@@ -2857,6 +2857,7 @@ preprocess_constraints (int n_operands, int n_alternatives,
for (j = 0; j < n_alternatives; j++, op_alt += n_operands)
{
op_alt[i].cl = NO_REGS;
+ op_alt[i].register_filters = 0;
op_alt[i].constraint = p;
op_alt[i].matches = -1;
op_alt[i].matched = -1;
@@ -2919,7 +2920,12 @@ preprocess_constraints (int n_operands, int n_alternatives,
case CT_REGISTER:
cl = reg_class_for_constraint (cn);
if (cl != NO_REGS)
- op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl];
+ {
+ op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl];
+ auto filter_id = get_register_filter_id (cn);
+ if (filter_id >= 0)
+ op_alt[i].register_filters |= 1U << filter_id;
+ }
break;
case CT_CONST_INT:
@@ -3219,13 +3225,17 @@ constrain_operands (int strict, alternative_mask alternatives)
enum reg_class cl = reg_class_for_constraint (cn);
if (cl != NO_REGS)
{
+ auto *filter = get_register_filter (cn);
if (strict < 0
|| (strict == 0
&& REG_P (op)
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)
|| (strict == 0 && GET_CODE (op) == SCRATCH)
|| (REG_P (op)
- && reg_fits_class_p (op, cl, offset, mode)))
+ && reg_fits_class_p (op, cl, offset, mode)
+ && (!filter
+ || TEST_HARD_REG_BIT (*filter,
+ REGNO (op) + offset))))
win = true;
}
diff --git a/gcc/recog.h b/gcc/recog.h
index c6ef619..5c801e7 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -42,6 +42,7 @@ enum op_type {
OP_INOUT
};
+#ifndef GENERATOR_FILE
struct operand_alternative
{
/* Pointer to the beginning of the constraint string for this alternative,
@@ -62,6 +63,11 @@ struct operand_alternative
matches this one. */
int matched : 8;
+ /* Bit ID is set if the constraint string includes a register constraint with
+ register filter ID. Use test_register_filters (REGISTER_FILTERS, REGNO)
+ to test whether REGNO is a valid start register for the operand. */
+ unsigned int register_filters : MAX (NUM_REGISTER_FILTERS, 1);
+
/* Nonzero if '&' was found in the constraint string. */
unsigned int earlyclobber : 1;
/* Nonzero if TARGET_MEM_CONSTRAINT was found in the constraint
@@ -72,8 +78,6 @@ struct operand_alternative
/* Nonzero if 'X' was found in the constraint string, or if the constraint
string for this alternative was empty. */
unsigned int anything_ok : 1;
-
- unsigned int unused : 12;
};
/* Return the class for operand I of alternative ALT, taking matching
@@ -85,6 +89,18 @@ alternative_class (const operand_alternative *alt, int i)
return alt[i].matches >= 0 ? alt[alt[i].matches].cl : alt[i].cl;
}
+/* Return the mask of register filters that should be applied to operand I
+ of alternative ALT, taking matching constraints into account. */
+
+inline unsigned int
+alternative_register_filters (const operand_alternative *alt, int i)
+{
+ return (alt[i].matches >= 0
+ ? alt[alt[i].matches].register_filters
+ : alt[i].register_filters);
+}
+#endif
+
/* A class for substituting one rtx for another within an instruction,
or for recursively simplifying the instruction as-is. Derived classes
can record or filter certain decisions. */
@@ -242,9 +258,11 @@ extern void extract_insn (rtx_insn *);
extern void extract_constrain_insn (rtx_insn *insn);
extern void extract_constrain_insn_cached (rtx_insn *);
extern void extract_insn_cached (rtx_insn *);
+#ifndef GENERATOR_FILE
extern void preprocess_constraints (int, int, const char **,
operand_alternative *, rtx **);
extern const operand_alternative *preprocess_insn_constraints (unsigned int);
+#endif
extern void preprocess_constraints (rtx_insn *);
extern rtx_insn *peep2_next_insn (int);
extern bool peep2_regno_dead_p (int, int);
@@ -380,6 +398,7 @@ struct recog_data_d
extern struct recog_data_d recog_data;
+#ifndef GENERATOR_FILE
extern const operand_alternative *recog_op_alt;
/* Return a pointer to an array in which index OP describes the constraints
@@ -393,6 +412,7 @@ which_op_alt ()
recog_data.n_alternatives - 1));
return &recog_op_alt[which_alternative * recog_data.n_operands];
}
+#endif
/* A table defined in insn-output.cc that give information about
each insn-code value. */