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.
This commit is contained in:
Richard Sandiford 2023-11-21 15:39:09 +00:00
parent 09a85191d0
commit 8265164810
2 changed files with 34 additions and 4 deletions

View file

@ -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;
}

View file

@ -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. */