This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Getting rid of constrain_asm_operands


This is the next part of the extract_insn changes.  This patch eliminates
the constrain_asm_operands function in reg-stack.  Most of the work done
by it is now done by contrain_operands which can now handle asm statements,
and the rest of the work (analyzing the constraints) is done by a new
function "preprocess_constraints".  There are many places in the compiler
that have to parse constraint strings; quite a few of those could probably
be converted to use this function.  It might be extended to gather other
information as well (e.g., call operands_match_p for all pairs with matching
constraints).
One drawback of the patch is that it introduces an arbitrary value
MAX_RECOG_ALTERNATIVES.  The chosen value (30) should be large enough and
can be increased if it ever turns out to be a problem.

The patch for final.c just removes some code that ought to be handled
transparently by extract_insn.

The patch was tested by building glibc-2.0.103 with it.  No errors in "make
check".

Bernd

	* final.c (cleanup_subreg_operands): Delete some unused code.

	* recog.h (MAX_RECOG_ALTERNATIVES): New macro.
	(struct insn_alternative): New structure definition.
	(recog_op_alt): Declare variable.
	(preprocess_constraints): Declare function.
	* recog.c (recog_op_alt): New variable.
	(extract_insn): Verify number of alternatives is in range.
	(preprocess_constraints): New function.
	* reg-stack.c: Include recog.h.
	(constrain_asm_operands): Delete.
	(get_asm_operand_lengths): Delete.
	(get_asm_operand_n_inputs): New function.
	(record_asm_reg_life): Delete OPERANDS, CONSTRAINTS, N_INPUTS and
	N_OUTPUTS args.  All callers changed.
	Compute number of inputs and outputs here by calling
	get_asm_operand_n_inputs.
	Instead of constrain_asm_operands, call extract_insn,
	constrain_operands and preprocess_constaints.  Use information
	computed by these functions throughout.
	(record_reg_life): Delete code that is unused due to changes in
	record_asm_reg_life.
	(subst_asm_stack_regs): Delete OPERANDS, OPERAND_LOC, CONSTRAINTS,
	N_INPUTS and N_OUTPUTS args.  All callers changed.
	Similar changes as in record_asm_reg_life.
	(subst_stack_regs): Move n_operands declaration into the if statement
	where it's used.
	Delete code that is unused due to changes in subst_asm_stack_regs.
	* stmt.c (expand_asm_operands): Verify number of alternatives is in
	range.
	* Makefile.in (reg-stack.o): Depend on recog.h.
	
Index: final.c
===================================================================
RCS file: /usr/local/cvs/gcs/gcc/final.c,v
retrieving revision 1.1.1.39
diff -u -p -r1.1.1.39 final.c
--- final.c	1998/11/13 10:03:17	1.1.1.39
+++ final.c	1998/11/21 12:18:19
@@ -3029,23 +3029,8 @@ void
 cleanup_subreg_operands (insn)
      rtx insn;
 {
-  int insn_code_number, i;
+  int i;
 
-  /* Ignore things we can not handle.  */
-  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
-      || GET_CODE (PATTERN (insn)) == USE
-      || GET_CODE (PATTERN (insn)) == ADDR_VEC
-      || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
-      || GET_CODE (PATTERN (insn)) == ASM_INPUT
-      || asm_noperands (PATTERN (insn)) >= 0)
-    return;
-
-  /* Try to recognize the instruction.
-     If successful, verify that the operands satisfy the
-     constraints for the instruction.  Crash if they don't,
-     since `reload' should have changed them so that they do.  */
-
-  insn_code_number = recog_memoized (insn);
   extract_insn (insn);
   for (i = 0; i < recog_n_operands; i++)
     {
Index: recog.c
===================================================================
RCS file: /usr/local/cvs/gcs/gcc/recog.c,v
retrieving revision 1.1.1.19
diff -u -p -r1.1.1.19 recog.c
--- recog.c	1998/11/05 18:44:47	1.1.1.19
+++ recog.c	1998/11/08 13:23:17
@@ -96,6 +96,10 @@ enum op_type recog_op_type[MAX_RECOG_OPE
 char recog_operand_address_p[MAX_RECOG_OPERANDS];
 #endif
 
+/* Contains a vector of operand_alternative structures for every operand.
+   Set up by preprocess_constraints.  */
+struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
+
 /* On return from `constrain_operands', indicate which alternative
    was satisfied.  */
 
@@ -1803,8 +1807,115 @@ extract_insn (insn)
     recog_op_type[i] = (recog_constraints[i][0] == '=' ? OP_OUT
 			: recog_constraints[i][0] == '+' ? OP_INOUT
 			: OP_IN);
+
+  if (recog_n_alternatives > MAX_RECOG_ALTERNATIVES)
+    abort ();
 }
 
+/* After calling extract_insn, you can use this function to extract some
+   information from the constraint strings into a more usable form.
+   The collected data is stored in recog_op_alt.  */
+void
+preprocess_constraints ()
+{
+  int i;
+
+  for (i = 0; i < recog_n_operands; i++)
+    {
+      int j;
+      struct operand_alternative *op_alt;
+      char *p = recog_constraints[i];
+
+      op_alt = recog_op_alt[i];
+
+      for (j = 0; j < recog_n_alternatives; j++)
+	{
+	  op_alt[j].cls = NO_REGS;
+	  op_alt[j].constraint = p;
+	  op_alt[j].matches = -1;
+	  op_alt[j].matched = -1;
+
+	  if (*p == '\0' || *p == ',')
+	    {
+	      op_alt[j].anything_ok = 1;
+	      continue;
+	    }
+
+	  for (;;)
+	    {
+	      char c = *p++;
+	      if (c == '#')
+		do
+		  c = *p++;
+		while (c != ',' && c != '\0');
+	      if (c == ',' || c == '\0')
+		break;
+
+	      switch (c)
+		{
+		case '=': case '+': case '*': case '%':
+		case 'E': case 'F': case 'G': case 'H':
+		case 's': case 'i': case 'n':
+		case 'I': case 'J': case 'K': case 'L':
+		case 'M': case 'N': case 'O': case 'P':
+#ifdef EXTRA_CONSTRAINT
+		case 'Q': case 'R': case 'S': case 'T': case 'U':
+#endif
+		  /* These don't say anything we care about.  */
+		  break;
+
+		case '?':
+		  op_alt[j].reject += 6;
+		  break;
+		case '!':
+		  op_alt[j].reject += 600;
+		  break;
+		case '&':
+		  op_alt[j].earlyclobber = 1;
+		  break;		  
+
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+		  op_alt[j].matches = c - '0';
+		  op_alt[op_alt[j].matches].matched = i;
+		  break;
+
+		case 'm':
+		  op_alt[j].memory_ok = 1;
+		  break;
+		case '<':
+		  op_alt[j].decmem_ok = 1;
+		  break;
+		case '>':
+		  op_alt[j].incmem_ok = 1;
+		  break;
+		case 'V':
+		  op_alt[j].nonoffmem_ok = 1;
+		  break;
+		case 'o':
+		  op_alt[j].offmem_ok = 1;
+		  break;
+		case 'X':
+		  op_alt[j].anything_ok = 1;
+		  break;
+
+		case 'p':
+		  op_alt[j].cls = reg_class_subunion[(int) op_alt[j].cls][(int) BASE_REG_CLASS];
+		  break;
+
+		case 'g': case 'r':
+		  op_alt[j].cls = reg_class_subunion[(int) op_alt[j].cls][(int) GENERAL_REGS];
+		  break;
+
+		default:
+		  op_alt[j].cls = reg_class_subunion[(int) op_alt[j].cls][(int) REG_CLASS_FROM_LETTER (c)];
+		  break;
+		}
+	    }
+	}
+    }
+}
+ 
 #ifdef REGISTER_CONSTRAINTS
 
 /* Check the operands of an insn against the insn's operand constraints
Index: reg-stack.c
===================================================================
RCS file: /usr/local/cvs/gcs/gcc/reg-stack.c,v
retrieving revision 1.1.1.19
diff -u -p -r1.1.1.19 reg-stack.c
--- reg-stack.c	1998/10/12 10:44:12	1.1.1.19
+++ reg-stack.c	1998/11/08 15:05:12
@@ -166,6 +166,7 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "insn-flags.h"
+#include "recog.h"
 #include "toplev.h"
 
 #ifdef STACK_REGS
@@ -241,14 +242,11 @@ static void straighten_stack		PROTO((rtx
 static void pop_stack			PROTO((stack, int));
 static void record_label_references	PROTO((rtx, rtx));
 static rtx *get_true_reg		PROTO((rtx *));
-static int constrain_asm_operands	PROTO((int, rtx *, char **, int *,
-					       enum reg_class *));
 
-static void record_asm_reg_life		PROTO((rtx,stack, rtx *, char **,
-					       int, int));
+static void record_asm_reg_life		PROTO((rtx, stack));
 static void record_reg_life_pat		PROTO((rtx, HARD_REG_SET *,
 					       HARD_REG_SET *, int));
-static void get_asm_operand_lengths	PROTO((rtx, int, int *, int *));
+static int get_asm_operand_n_inputs	PROTO((rtx));
 static void record_reg_life		PROTO((rtx, int, stack));
 static void find_blocks			PROTO((rtx));
 static rtx stack_result			PROTO((tree));
@@ -263,8 +261,7 @@ static void move_for_stack_reg		PROTO((r
 static void swap_rtx_condition		PROTO((rtx));
 static void compare_for_stack_reg	PROTO((rtx, stack, rtx));
 static void subst_stack_regs_pat	PROTO((rtx, stack, rtx));
-static void subst_asm_stack_regs	PROTO((rtx, stack, rtx *, rtx **,
-					       char **, int, int));
+static void subst_asm_stack_regs	PROTO((rtx, stack));
 static void subst_stack_regs		PROTO((rtx, stack));
 static void change_stack		PROTO((rtx, stack, stack, rtx (*) ()));
 
@@ -607,342 +604,57 @@ get_true_reg (pat)
       }
 }
 
-/* Scan the OPERANDS and OPERAND_CONSTRAINTS of an asm_operands.
-   N_OPERANDS is the total number of operands.  Return which alternative
-   matched, or -1 is no alternative matches.
-
-   OPERAND_MATCHES is an array which indicates which operand this
-   operand matches due to the constraints, or -1 if no match is required.
-   If two operands match by coincidence, but are not required to match by
-   the constraints, -1 is returned.
-
-   OPERAND_CLASS is an array which indicates the smallest class
-   required by the constraints.  If the alternative that matches calls
-   for some class `class', and the operand matches a subclass of `class',
-   OPERAND_CLASS is set to `class' as required by the constraints, not to
-   the subclass. If an alternative allows more than one class,
-   OPERAND_CLASS is set to the smallest class that is a union of the
-   allowed classes.  */
-
-static int
-constrain_asm_operands (n_operands, operands, operand_constraints,
-			operand_matches, operand_class)
-     int n_operands;
-     rtx *operands;
-     char **operand_constraints;
-     int *operand_matches;
-     enum reg_class *operand_class;
-{
-  char **constraints = (char **) alloca (n_operands * sizeof (char *));
-  char *q;
-  int this_alternative, this_operand;
-  int n_alternatives;
-  int j;
-
-  for (j = 0; j < n_operands; j++)
-    constraints[j] = operand_constraints[j];
-
-  /* Compute the number of alternatives in the operands.  reload has
-     already guaranteed that all operands have the same number of
-     alternatives.  */
-
-  if (n_operands == 0)
-    n_alternatives = 0;
-  else
-    {
-      n_alternatives = 1;
-      for (q = constraints[0]; *q; q++)
-	n_alternatives += (*q == ',');
-    }
-
-  this_alternative = 0;
-  while (this_alternative < n_alternatives)
-    {
-      int lose = 0;
-      int i;
-
-      /* No operands match, no narrow class requirements yet.  */
-      for (i = 0; i < n_operands; i++)
-	{
-	  operand_matches[i] = -1;
-	  operand_class[i] = NO_REGS;
-	}
-
-      for (this_operand = 0; this_operand < n_operands; this_operand++)
-	{
-	  rtx op = operands[this_operand];
-	  enum machine_mode mode = GET_MODE (op);
-	  char *p = constraints[this_operand];
-	  int offset = 0;
-	  int win = 0;
-	  int c;
-
-	  if (GET_CODE (op) == SUBREG)
-	    {
-	      if (GET_CODE (SUBREG_REG (op)) == REG
-		  && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
-		offset = SUBREG_WORD (op);
-	      op = SUBREG_REG (op);
-	    }
-
-	  /* An empty constraint or empty alternative
-	     allows anything which matched the pattern.  */
-	  if (*p == 0 || *p == ',')
-	    win = 1;
-
-	  while (*p && (c = *p++) != ',')
-	    switch (c)
-	      {
-	      case '=':
-	      case '+':
-	      case '?':
-	      case '&':
-	      case '!':
-	      case '*':
-	      case '%':
-		/* Ignore these.  */
-		break;
-
-	      case '#':
-		/* Ignore rest of this alternative.  */
-		while (*p && *p != ',') p++;
-		break;
-
-	      case '0':
-	      case '1':
-	      case '2':
-	      case '3':
-	      case '4':
-	      case '5':
-		/* This operand must be the same as a previous one.
-		   This kind of constraint is used for instructions such
-		   as add when they take only two operands.
-
-		   Note that the lower-numbered operand is passed first.  */
-
-		if (operands_match_p (operands[c - '0'],
-				      operands[this_operand]))
-		  {
-		    operand_matches[this_operand] = c - '0';
-		    win = 1;
-		  }
-		break;
-
-	      case 'p':
-		/* p is used for address_operands.  Since this is an asm,
-		   just to make sure that the operand is valid for Pmode.  */
-
-		if (strict_memory_address_p (Pmode, op))
-		  win = 1;
-		break;
-
-	      case 'g':
-		/* Anything goes unless it is a REG and really has a hard reg
-		   but the hard reg is not in the class GENERAL_REGS.  */
-		if (GENERAL_REGS == ALL_REGS
-		    || GET_CODE (op) != REG
-		    || reg_fits_class_p (op, GENERAL_REGS, offset, mode))
-		  {
-		    if (GET_CODE (op) == REG)
-		      operand_class[this_operand]
-			= reg_class_subunion[(int) operand_class[this_operand]][(int) GENERAL_REGS];
-		    win = 1;
-		  }
-		break;
-
-	      case 'r':
-		if (GET_CODE (op) == REG
-		    && (GENERAL_REGS == ALL_REGS
-			|| reg_fits_class_p (op, GENERAL_REGS, offset, mode)))
-		  {
-		    operand_class[this_operand]
-		      = reg_class_subunion[(int) operand_class[this_operand]][(int) GENERAL_REGS];
-		    win = 1;
-		  }
-		break;
-
-	      case 'X':
-		/* This is used for a MATCH_SCRATCH in the cases when we
-		   don't actually need anything.  So anything goes any time.  */
-		win = 1;
-		break;
-
-	      case 'm':
-		if (GET_CODE (op) == MEM)
-		  win = 1;
-		break;
-
-	      case '<':
-		if (GET_CODE (op) == MEM
-		    && (GET_CODE (XEXP (op, 0)) == PRE_DEC
-			|| GET_CODE (XEXP (op, 0)) == POST_DEC))
-		  win = 1;
-		break;
-
-	      case '>':
-		if (GET_CODE (op) == MEM
-		    && (GET_CODE (XEXP (op, 0)) == PRE_INC
-			|| GET_CODE (XEXP (op, 0)) == POST_INC))
-		  win = 1;
-		break;
-
-	      case 'E':
-		/* Match any CONST_DOUBLE, but only if
-		   we can examine the bits of it reliably.  */
-		if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-		     || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
-		    && GET_CODE (op) != VOIDmode && ! flag_pretend_float)
-		  break;
-		if (GET_CODE (op) == CONST_DOUBLE)
-		  win = 1;
-		break;
-
-	      case 'F':
-		if (GET_CODE (op) == CONST_DOUBLE)
-		  win = 1;
-		break;
-
-	      case 'G':
-	      case 'H':
-		if (GET_CODE (op) == CONST_DOUBLE
-		    && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
-		  win = 1;
-		break;
-
-	      case 's':
-		if (GET_CODE (op) == CONST_INT
-		    || (GET_CODE (op) == CONST_DOUBLE
-			&& GET_MODE (op) == VOIDmode))
-		  break;
-		/* Fall through */
-	      case 'i':
-		if (CONSTANT_P (op))
-		  win = 1;
-		break;
-
-	      case 'n':
-		if (GET_CODE (op) == CONST_INT
-		    || (GET_CODE (op) == CONST_DOUBLE
-			&& GET_MODE (op) == VOIDmode))
-		  win = 1;
-		break;
-
-	      case 'I':
-	      case 'J':
-	      case 'K':
-	      case 'L':
-	      case 'M':
-	      case 'N':
-	      case 'O':
-	      case 'P':
-		if (GET_CODE (op) == CONST_INT
-		    && CONST_OK_FOR_LETTER_P (INTVAL (op), c))
-		  win = 1;
-		break;
-
-#ifdef EXTRA_CONSTRAINT
-              case 'Q':
-              case 'R':
-              case 'S':
-              case 'T':
-              case 'U':
-		if (EXTRA_CONSTRAINT (op, c))
-		  win = 1;
-		break;
-#endif
-
-	      case 'V':
-		if (GET_CODE (op) == MEM && ! offsettable_memref_p (op))
-		  win = 1;
-		break;
-
-	      case 'o':
-		if (offsettable_memref_p (op))
-		  win = 1;
-		break;
-
-	      default:
-		if (GET_CODE (op) == REG
-		    && reg_fits_class_p (op, REG_CLASS_FROM_LETTER (c),
-					 offset, mode))
-		  {
-		    operand_class[this_operand]
-		      = reg_class_subunion[(int)operand_class[this_operand]][(int) REG_CLASS_FROM_LETTER (c)];
-		    win = 1;
-		  }
-	      }
-
-	  constraints[this_operand] = p;
-	  /* If this operand did not win somehow,
-	     this alternative loses.  */
-	  if (! win)
-	    lose = 1;
-	}
-      /* This alternative won; the operands are ok.
-	 Change whichever operands this alternative says to change.  */
-      if (! lose)
-	break;
-
-      this_alternative++;
-    }
-
-  /* For operands constrained to match another operand, copy the other
-     operand's class to this operand's class.  */
-  for (j = 0; j < n_operands; j++)
-    if (operand_matches[j] >= 0)
-      operand_class[j] = operand_class[operand_matches[j]];
-
-  return this_alternative == n_alternatives ? -1 : this_alternative;
-}
-
 /* Record the life info of each stack reg in INSN, updating REGSTACK.
-   N_INPUTS is the number of inputs; N_OUTPUTS the outputs.  CONSTRAINTS
-   is an array of the constraint strings used in the asm statement.
+   N_INPUTS is the number of inputs; N_OUTPUTS the outputs.
    OPERANDS is an array of all operands for the insn, and is assumed to
    contain all output operands, then all inputs operands.
 
    There are many rules that an asm statement for stack-like regs must
    follow.  Those rules are explained at the top of this file: the rule
-   numbers below refer to that explanation.  */
+   numbers below refer to that explanation.  */
 
 static void
-record_asm_reg_life (insn, regstack, operands, constraints,
-		     n_inputs, n_outputs)
+record_asm_reg_life (insn, regstack)
      rtx insn;
      stack regstack;
-     rtx *operands;
-     char **constraints;
-     int n_inputs, n_outputs;
 {
   int i;
-  int n_operands = n_inputs + n_outputs;
-  int first_input = n_outputs;
   int n_clobbers;
   int malformed_asm = 0;
   rtx body = PATTERN (insn);
 
-  int *operand_matches = (int *) alloca (n_operands * sizeof (int));
-
-  enum reg_class *operand_class 
-    = (enum reg_class *) alloca (n_operands * sizeof (enum reg_class));
-
   int reg_used_as_output[FIRST_PSEUDO_REGISTER];
   int implicitly_dies[FIRST_PSEUDO_REGISTER];
+  int alt;
 
   rtx *clobber_reg;
+  int n_inputs, n_outputs;
 
   /* Find out what the constraints require.  If no constraint
      alternative matches, this asm is malformed.  */
-  i = constrain_asm_operands (n_operands, operands, constraints,
-			      operand_matches, operand_class);
-  if (i < 0)
-    malformed_asm = 1;
+  extract_insn (insn);
+  constrain_operands (1);
+  alt = which_alternative;
+
+  preprocess_constraints ();
+
+  n_inputs = get_asm_operand_n_inputs (body);
+  n_outputs = recog_n_operands - n_inputs;
+
+  if (alt < 0)
+    {
+      malformed_asm = 1;
+      /* Avoid further trouble with this insn.  */
+      PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
+      PUT_MODE (insn, VOIDmode);
+      return;
+    }
 
   /* Strip SUBREGs here to make the following code simpler.  */
-  for (i = 0; i < n_operands; i++)
-    if (GET_CODE (operands[i]) == SUBREG
-	&& GET_CODE (SUBREG_REG (operands[i])) == REG)
-      operands[i] = SUBREG_REG (operands[i]);
+  for (i = 0; i < recog_n_operands; i++)
+    if (GET_CODE (recog_operand[i]) == SUBREG
+	&& GET_CODE (SUBREG_REG (recog_operand[i])) == REG)
+      recog_operand[i] = SUBREG_REG (recog_operand[i]);
 
   /* Set up CLOBBER_REG.  */
 
@@ -978,15 +690,15 @@ record_asm_reg_life (insn, regstack, ope
 
   bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output));
   for (i = 0; i < n_outputs; i++)
-    if (STACK_REG_P (operands[i]))
+    if (STACK_REG_P (recog_operand[i]))
       {
-	if (reg_class_size[(int) operand_class[i]] != 1)
+	if (reg_class_size[(int) recog_op_alt[i][alt].cls] != 1)
 	  {
 	    error_for_asm (insn, "Output constraint %d must specify a single register", i);
 	    malformed_asm = 1;
 	  }
         else
-	  reg_used_as_output[REGNO (operands[i])] = 1;
+	  reg_used_as_output[REGNO (recog_operand[i])] = 1;
       }
 
 
@@ -1011,19 +723,19 @@ record_asm_reg_life (insn, regstack, ope
      popped.  */
 
   bzero ((char *) implicitly_dies, sizeof (implicitly_dies));
-  for (i = first_input; i < first_input + n_inputs; i++)
-    if (STACK_REG_P (operands[i]))
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_operand[i]))
       {
 	/* An input reg is implicitly popped if it is tied to an
 	   output, or if there is a CLOBBER for it.  */
 	int j;
 
 	for (j = 0; j < n_clobbers; j++)
-	  if (operands_match_p (clobber_reg[j], operands[i]))
+	  if (operands_match_p (clobber_reg[j], recog_operand[i]))
 	    break;
 
-	if (j < n_clobbers || operand_matches[i] >= 0)
-	  implicitly_dies[REGNO (operands[i])] = 1;
+	if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+	  implicitly_dies[REGNO (recog_operand[i])] = 1;
       }
 
   /* Search for first non-popped reg.  */
@@ -1049,13 +761,13 @@ record_asm_reg_life (insn, regstack, ope
      ???  Detect this more deterministically by having constraint_asm_operands
      record any earlyclobber.  */
 
-  for (i = first_input; i < first_input + n_inputs; i++)
-    if (operand_matches[i] == -1)
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (recog_op_alt[i][alt].matches == -1)
       {
 	int j;
 
 	for (j = 0; j < n_outputs; j++)
-	  if (operands_match_p (operands[j], operands[i]))
+	  if (operands_match_p (recog_operand[j], recog_operand[i]))
 	    {
 	      error_for_asm (insn,
 			     "Output operand %d must use `&' constraint", j);
@@ -1074,7 +786,7 @@ record_asm_reg_life (insn, regstack, ope
   /* Process all outputs */
   for (i = 0; i < n_outputs; i++)
     {
-      rtx op = operands[i];
+      rtx op = recog_operand[i];
 
       if (! STACK_REG_P (op))
 	{
@@ -1096,11 +808,12 @@ record_asm_reg_life (insn, regstack, ope
     }
 
   /* Process all inputs */
-  for (i = first_input; i < first_input + n_inputs; i++)
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
     {
-      if (! STACK_REG_P (operands[i]))
+      rtx op = recog_operand[i];
+      if (! STACK_REG_P (op))
 	{
-	  if (stack_regs_mentioned_p (operands[i]))
+	  if (stack_regs_mentioned_p (op))
 	    abort ();
 	  else
 	    continue;
@@ -1110,13 +823,12 @@ record_asm_reg_life (insn, regstack, ope
 	 But don't record a death note if there is already a death note,
 	 or if the input is also an output.  */
 
-      if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))
-	  && operand_matches[i] == -1
-	  && find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX)
-	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, operands[i],
-					      REG_NOTES (insn));
+      if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (op))
+	  && recog_op_alt[i][alt].matches == -1
+	  && find_regno_note (insn, REG_DEAD, REGNO (op)) == NULL_RTX)
+	REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, op, REG_NOTES (insn));
 
-      SET_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]));
+      SET_HARD_REG_BIT (regstack->reg_set, REGNO (op));
     }
 }
 
@@ -1178,29 +890,25 @@ record_reg_life_pat (pat, src, dest, dou
    N_INPUTS and N_OUTPUTS are pointers to ints into which the results are
    placed.  */
 
-static void
-get_asm_operand_lengths (body, n_operands, n_inputs, n_outputs)
+static int
+get_asm_operand_n_inputs (body)
      rtx body;
-     int n_operands;
-     int *n_inputs, *n_outputs;
 {
   if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS)
-    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body));
+    return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body));
 
   else if (GET_CODE (body) == ASM_OPERANDS)
-    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (body);
+    return ASM_OPERANDS_INPUT_LENGTH (body);
 
   else if (GET_CODE (body) == PARALLEL
 	   && GET_CODE (XVECEXP (body, 0, 0)) == SET)
-    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (SET_SRC (XVECEXP (body, 0, 0)));
+    return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (XVECEXP (body, 0, 0)));
 
   else if (GET_CODE (body) == PARALLEL
 	   && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)
-    *n_inputs = ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0));
-  else
-    abort ();
+    return ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0));
 
-  *n_outputs = n_operands - *n_inputs;
+  abort ();
 }
 
 /* Scan INSN, which is in BLOCK, and record the life & death of stack
@@ -1244,18 +952,7 @@ record_reg_life (insn, block, regstack)
   n_operands = asm_noperands (PATTERN (insn));
   if (n_operands >= 0)
     {
-      /* This insn is an `asm' with operands.  Decode the operands,
-	 decide how many are inputs, and record the life information.  */
-
-      rtx operands[MAX_RECOG_OPERANDS];
-      rtx body = PATTERN (insn);
-      int n_inputs, n_outputs;
-      char **constraints = (char **) alloca (n_operands * sizeof (char *));
-
-      decode_asm_operands (body, operands, NULL_PTR, constraints, NULL_PTR);
-      get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
-      record_asm_reg_life (insn, regstack, operands, constraints,
-			   n_inputs, n_outputs);
+      record_asm_reg_life (insn, regstack);
       return;
     }
 
@@ -2417,12 +2114,7 @@ subst_stack_regs_pat (insn, regstack, pa
 
 /* Substitute hard regnums for any stack regs in INSN, which has
    N_INPUTS inputs and N_OUTPUTS outputs.  REGSTACK is the stack info
-   before the insn, and is updated with changes made here.  CONSTRAINTS is
-   an array of the constraint strings used in the asm statement.
-
-   OPERANDS is an array of the operands, and OPERANDS_LOC is a
-   parallel array of where the operands were found.  The output operands
-   all precede the input operands.
+   before the insn, and is updated with changes made here.
 
    There are several requirements and assumptions about the use of
    stack-like regs in asm statements.  These rules are enforced by
@@ -2431,22 +2123,13 @@ subst_stack_regs_pat (insn, regstack, pa
    requirements, since record_asm_stack_regs removes any problem asm.  */
 
 static void
-subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
-		      n_inputs, n_outputs)
+subst_asm_stack_regs (insn, regstack)
      rtx insn;
      stack regstack;
-     rtx *operands, **operands_loc;
-     char **constraints;
-     int n_inputs, n_outputs;
 {
-  int n_operands = n_inputs + n_outputs;
-  int first_input = n_outputs;
   rtx body = PATTERN (insn);
+  int alt;
 
-  int *operand_matches = (int *) alloca (n_operands * sizeof (int));
-  enum reg_class *operand_class 
-    = (enum reg_class *) alloca (n_operands * sizeof (enum reg_class));
-
   rtx *note_reg;		/* Array of note contents */
   rtx **note_loc;		/* Address of REG field of each note */
   enum reg_note *note_kind;	/* The type of each note */
@@ -2459,24 +2142,31 @@ subst_asm_stack_regs (insn, regstack, op
   int n_clobbers;
   rtx note;
   int i;
+  int n_inputs, n_outputs;
 
   /* Find out what the constraints required.  If no constraint
      alternative matches, that is a compiler bug: we should have caught
      such an insn during the life analysis pass (and reload should have
      caught it regardless).  */
+  extract_insn (insn);
+  constrain_operands (1);
+  alt = which_alternative;
+
+  preprocess_constraints ();
 
-  i = constrain_asm_operands (n_operands, operands, constraints,
-			      operand_matches, operand_class);
-  if (i < 0)
+  n_inputs = get_asm_operand_n_inputs (body);
+  n_outputs = recog_n_operands - n_inputs;
+  
+  if (alt < 0)
     abort ();
 
   /* Strip SUBREGs here to make the following code simpler.  */
-  for (i = 0; i < n_operands; i++)
-    if (GET_CODE (operands[i]) == SUBREG
-	&& GET_CODE (SUBREG_REG (operands[i])) == REG)
+  for (i = 0; i < recog_n_operands; i++)
+    if (GET_CODE (recog_operand[i]) == SUBREG
+	&& GET_CODE (SUBREG_REG (recog_operand[i])) == REG)
       {
-	operands_loc[i] = & SUBREG_REG (operands[i]);
-	operands[i] = SUBREG_REG (operands[i]);
+	recog_operand_loc[i] = & SUBREG_REG (recog_operand[i]);
+	recog_operand[i] = SUBREG_REG (recog_operand[i]);
       }
 
   /* Set up NOTE_REG, NOTE_LOC and NOTE_KIND.  */
@@ -2546,34 +2236,35 @@ subst_asm_stack_regs (insn, regstack, op
 
   /* Put the input regs into the desired place in TEMP_STACK.  */
 
-  for (i = first_input; i < first_input + n_inputs; i++)
-    if (STACK_REG_P (operands[i])
-	&& reg_class_subset_p (operand_class[i], FLOAT_REGS)
-	&& operand_class[i] != FLOAT_REGS)
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_operand[i])
+	&& reg_class_subset_p (recog_op_alt[i][alt].cls,
+			       FLOAT_REGS)
+	&& recog_op_alt[i][alt].cls != FLOAT_REGS)
       {
 	/* If an operand needs to be in a particular reg in
 	   FLOAT_REGS, the constraint was either 't' or 'u'.  Since
 	   these constraints are for single register classes, and reload
 	   guaranteed that operand[i] is already in that class, we can
-	   just use REGNO (operands[i]) to know which actual reg this
+	   just use REGNO (recog_operand[i]) to know which actual reg this
 	   operand needs to be in.  */
 
-	int regno = get_hard_regnum (&temp_stack, operands[i]);
+	int regno = get_hard_regnum (&temp_stack, recog_operand[i]);
 
 	if (regno < 0)
 	  abort ();
 
-	if (regno != REGNO (operands[i]))
+	if (regno != REGNO (recog_operand[i]))
 	  {
-	    /* operands[i] is not in the right place.  Find it
+	    /* recog_operand[i] is not in the right place.  Find it
 	       and swap it with whatever is already in I's place.
-	       K is where operands[i] is now.  J is where it should
+	       K is where recog_operand[i] is now.  J is where it should
 	       be.  */
 	    int j, k, temp;
 
 	    k = temp_stack.top - (regno - FIRST_STACK_REG);
 	    j = (temp_stack.top
-		 - (REGNO (operands[i]) - FIRST_STACK_REG));
+		 - (REGNO (recog_operand[i]) - FIRST_STACK_REG));
 
 	    temp = temp_stack.reg[k];
 	    temp_stack.reg[k] = temp_stack.reg[j];
@@ -2589,15 +2280,15 @@ subst_asm_stack_regs (insn, regstack, op
   /* Make the needed input register substitutions.  Do death notes and
      clobbers too, because these are for inputs, not outputs.  */
 
-  for (i = first_input; i < first_input + n_inputs; i++)
-    if (STACK_REG_P (operands[i]))
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_operand[i]))
       {
-	int regnum = get_hard_regnum (regstack, operands[i]);
+	int regnum = get_hard_regnum (regstack, recog_operand[i]);
 
 	if (regnum < 0)
 	  abort ();
 
-	replace_reg (operands_loc[i], regnum);
+	replace_reg (recog_operand_loc[i], regnum);
       }
 
   for (i = 0; i < n_notes; i++)
@@ -2629,21 +2320,21 @@ subst_asm_stack_regs (insn, regstack, op
 
   /* Now remove from REGSTACK any inputs that the asm implicitly popped.  */
 
-  for (i = first_input; i < first_input + n_inputs; i++)
-    if (STACK_REG_P (operands[i]))
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_operand[i]))
       {
 	/* An input reg is implicitly popped if it is tied to an
 	   output, or if there is a CLOBBER for it.  */
 	int j;
 
 	for (j = 0; j < n_clobbers; j++)
-	  if (operands_match_p (clobber_reg[j], operands[i]))
+	  if (operands_match_p (clobber_reg[j], recog_operand[i]))
 	    break;
 
-	if (j < n_clobbers || operand_matches[i] >= 0)
+	if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
 	  {
-	    /* operands[i] might not be at the top of stack.  But that's OK,
-	       because all we need to do is pop the right number of regs
+	    /* recog_operand[i] might not be at the top of stack.  But that's
+	       OK, because all we need to do is pop the right number of regs
 	       off of the top of the reg-stack.  record_asm_stack_regs
 	       guaranteed that all implicitly popped regs were grouped
 	       at the top of the reg-stack.  */
@@ -2664,7 +2355,7 @@ subst_asm_stack_regs (insn, regstack, op
       int j;
 
       for (j = 0; j < n_outputs; j++)
-	if (STACK_REG_P (operands[j]) && REGNO (operands[j]) == i)
+	if (STACK_REG_P (recog_operand[j]) && REGNO (recog_operand[j]) == i)
 	  {
 	    regstack->reg[++regstack->top] = i;
 	    SET_HARD_REG_BIT (regstack->reg_set, i);
@@ -2680,31 +2371,32 @@ subst_asm_stack_regs (insn, regstack, op
      in the death notes have already been substituted.  */
 
   for (i = 0; i < n_outputs; i++)
-    if (STACK_REG_P (operands[i]))
+    if (STACK_REG_P (recog_operand[i]))
       {
 	int j;
 
 	for (j = 0; j < n_notes; j++)
-	  if (REGNO (operands[i]) == REGNO (note_reg[j])
+	  if (REGNO (recog_operand[i]) == REGNO (note_reg[j])
 	      && note_kind[j] == REG_UNUSED)
 	    {
-	      insn = emit_pop_insn (insn, regstack, operands[i],
+	      insn = emit_pop_insn (insn, regstack, recog_operand[i],
 				    emit_insn_after);
 	      break;
 	    }
       }
 
-  for (i = first_input; i < first_input + n_inputs; i++)
-    if (STACK_REG_P (operands[i]))
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_operand[i]))
       {
 	int j;
 
 	for (j = 0; j < n_notes; j++)
-	  if (REGNO (operands[i]) == REGNO (note_reg[j])
+	  if (REGNO (recog_operand[i]) == REGNO (note_reg[j])
 	      && note_kind[j] == REG_DEAD
-	      && TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i])))
+	      && TEST_HARD_REG_BIT (regstack->reg_set,
+				    REGNO (recog_operand[i])))
 	    {
-	      insn = emit_pop_insn (insn, regstack, operands[i],
+	      insn = emit_pop_insn (insn, regstack, recog_operand[i],
 				    emit_insn_after);
 	      break;
 	    }
@@ -2723,7 +2415,6 @@ subst_stack_regs (insn, regstack)
 {
   register rtx *note_link, note;
   register int i;
-  int n_operands;
 
   if (GET_CODE (insn) == CALL_INSN)
    {
@@ -2755,25 +2446,14 @@ subst_stack_regs (insn, regstack)
 
   if (GET_MODE (insn) == QImode)
     {
-      n_operands = asm_noperands (PATTERN (insn));
+      int n_operands = asm_noperands (PATTERN (insn));
       if (n_operands >= 0)
 	{
 	  /* This insn is an `asm' with operands.  Decode the operands,
 	     decide how many are inputs, and do register substitution.
 	     Any REG_UNUSED notes will be handled by subst_asm_stack_regs.  */
 
-	  rtx operands[MAX_RECOG_OPERANDS];
-	  rtx *operands_loc[MAX_RECOG_OPERANDS];
-	  rtx body = PATTERN (insn);
-	  int n_inputs, n_outputs;
-	  char **constraints
-	    = (char **) alloca (n_operands * sizeof (char *));
-
-	  decode_asm_operands (body, operands, operands_loc,
-			       constraints, NULL_PTR);
-	  get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
-	  subst_asm_stack_regs (insn, regstack, operands, operands_loc,
-				constraints, n_inputs, n_outputs);
+	  subst_asm_stack_regs (insn, regstack);
 	  return;
 	}
 
Index: stmt.c
===================================================================
RCS file: /usr/local/cvs/gcs/gcc/stmt.c,v
retrieving revision 1.1.1.38
diff -u -p -r1.1.1.38 stmt.c
--- stmt.c	1998/11/21 12:08:43	1.1.1.38
+++ stmt.c	1998/11/21 12:40:36
@@ -1219,6 +1219,12 @@ expand_asm_operands (string, outputs, in
       int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp));
       tree next = inputs;
 
+      if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
+	{
+	  error ("too many alternatives in `asm'");
+	  return;
+	}
+      
       tmp = outputs;
       while (tmp)
 	{
Index: Makefile.in
===================================================================
RCS file: /usr/local/cvs/gcs/gcc/Makefile.in,v
retrieving revision 1.1.1.75
diff -u -p -r1.1.1.75 Makefile.in
--- Makefile.in	1998/11/28 10:27:41	1.1.1.75
+++ Makefile.in	1998/11/28 18:23:00
@@ -1535,7 +1535,7 @@ final.o : final.c $(CONFIG_H) system.h $
 recog.o : recog.c $(CONFIG_H) system.h $(RTL_H)  \
    $(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
    insn-flags.h insn-codes.h real.h toplev.h
-reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) \
+reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) recog.h \
    $(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h
 dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h
 
Index: recog.h
===================================================================
RCS file: /usr/local/cvs/gcs/gcc/recog.h,v
retrieving revision 1.1.1.7
diff -u -p -r1.1.1.7 recog.h
--- recog.h	1998/11/08 15:15:12	1.1.1.7
+++ recog.h	1998/11/28 18:37:59
@@ -18,6 +18,9 @@ along with GNU CC; see the file COPYING.
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
+/* Random number that should be large enough for all purposes.  */
+#define MAX_RECOG_ALTERNATIVES 30
+
 /* Types of operands.  */
 enum op_type {
   OP_IN,
@@ -25,6 +28,44 @@ enum op_type {
   OP_INOUT
 };
 
+struct operand_alternative
+{
+  /* Pointer to the beginning of the constraint string for this alternative,
+     for easier access by alternative number.  */
+  char *constraint;
+
+  /* The register class valid for this alternative (possibly NO_REGS).  */
+  enum reg_class cls;
+
+  /* "Badness" of this alternative, computed from number of '?' and '!'
+     characters in the constraint string.  */
+  unsigned int reject;
+
+  /* -1 if no matching constraint was found, or an operand number.  */
+  int matches;
+  /* The same information, but reversed: -1 if this operand is not
+     matched by any other, or the operand number of the operand that
+     matches this one.  */
+  int matched;
+
+  /* Nonzero if '&' was found in the constraint string.  */
+  unsigned int earlyclobber:1;
+  /* Nonzero if 'm' was found in the constraint string.  */
+  unsigned int memory_ok:1;  
+  /* Nonzero if 'o' was found in the constraint string.  */
+  unsigned int offmem_ok:1;  
+  /* Nonzero if 'V' was found in the constraint string.  */
+  unsigned int nonoffmem_ok:1;
+  /* Nonzero if '<' was found in the constraint string.  */
+  unsigned int decmem_ok:1;
+  /* Nonzero if '>' was found in the constraint string.  */
+  unsigned int incmem_ok:1;
+  /* Nonzero if 'X' was found in the constraint string, or if the constraint
+     string for this alternative was empty.  */
+  unsigned int anything_ok:1;
+};
+
+
 extern void init_recog			PROTO((void));
 extern void init_recog_no_volatile	PROTO((void));
 extern int recog_memoized		PROTO((rtx));
@@ -67,6 +108,7 @@ extern int recog			PROTO((rtx, rtx, int 
 extern void add_clobbers		PROTO((rtx, int));
 extern void insn_extract		PROTO((rtx));
 extern void extract_insn		PROTO((rtx));
+extern void preprocess_constraints	PROTO((void));
 
 /* Nonzero means volatile operands are recognized.  */
 extern int volatile_ok;
@@ -115,6 +157,10 @@ extern enum op_type recog_op_type[];
 /* Indexed by N, nonzero if operand N should be an address.  */
 extern char recog_operand_address_p[];
 #endif
+
+/* Contains a vector of operand_alternative structures for every operand.
+   Set up by preprocess_constraints.  */
+struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
 
 /* Access the output function for CODE.  */
 



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]