diff mbox series

[2/5] recog: Handle register filters

Message ID 20231112145229.2924713-3-richard.sandiford@arm.com
State New
Headers show
Series Add support for operand-specific alignment requirements | expand

Commit Message

Richard Sandiford Nov. 12, 2023, 2:52 p.m. UTC
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.
---
 gcc/recog.cc | 14 ++++++++++++--
 gcc/recog.h  | 24 ++++++++++++++++++++++--
 2 files changed, 34 insertions(+), 4 deletions(-)

Comments

Jeff Law Nov. 19, 2023, 9:51 p.m. UTC | #1
On 11/12/23 07:52, Richard Sandiford wrote:
> 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.
OK
jeff
diff mbox series

Patch

diff --git a/gcc/recog.cc b/gcc/recog.cc
index 3bd2d73c259..eaab79c25d7 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 c6ef619c5dd..5c801e7bb81 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.  */