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]
Other format: [Raw text]

RFA: constraint strings (Was: RFD: constraint letter suffixes)


-- 
--------------------------
SuperH (UK) Ltd.
2410 Aztec West / Almondsbury / BRISTOL / BS32 4QX
T:+44 1454 465658
Note: recog.c:constrain_operands and reload.c:find_reloads now both have a
loop of the form

	  do
	    switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
	      {
		/* do stuff... */
	      }
	  while (p += len, c);

Usually the three assignments would go into a block at the top level of the
loop, except there is no such block now, and creating it means re-indenting
several hundred lines of relatively conservative code in each loop.
I am open to do this re-indentation if you think it is a lesser evil
then these embedded assignemnts, but I thought at least for the review
it makes it easier to see what is going on without these massive
re-indentations.
There are some smaller and medium-sized re-indentations in this patch
though, the largest being in record_reg_classes, where again there
was a naked switch statement of some 150 lines in a while loop.

Regression tested on sh64-elf.
i686-pc-linux-gnu bootstrap in progress.

Tue Jan  7 20:07:26 2003  J"orn Rennecke <joern.rennecke@superh.com>

	* defaults.h (EXTRA_MEMORY_CONSTRAINT): Add STR argument.
	(EXTRA_ADDRESS_CONSTRAINT): Likewise.
	(CONSTRAINT_LEN): Provide default definition.
	(CONST_OK_FOR_CONSTRAINT_P): Likewise.
	(CONST_DOUBLE_OK_FOR_CONSTRAINT_P): Likewise.
	(EXTRA_CONSTRAINT_STR): Likewise.
	(REG_CLASS_FROM_CONSTRAINT): Define.
	* genoutput.c (check_constraint_len, constraint_len): New functions.
	(validate_insn_alternatives): Check CONSTRAINT_LEN for each
	constraint / modifier.
	(gen_insn): Call check_constraint_len.
	* local-alloc.c (block_alloc): Update to use new macros / pass
	second argument to EXTRA_{MEMORY,ADDRESS}_CONSTRAINT.
	* ra-build.c (handle_asm_insn): Likewise.
	* recog.c (asm_operand_ok, preprocess_constraints): Likewise.
	(constrain_operands, peep2_find_free_register): Likewise.
	* regclass.c (record_operand_costs, record_reg_classes): Likewise.
	* regmove.c (find_matches): Likewise.
	* reload.c (push_secondary_reload, find_reloads): Likewise.
	(alternative_allows_memconst): Likewise.
	* reload1.c (maybe_fix_stack_asms): Likewise.
	(reload_cse_simplify_operands): Likewise.
	* stmt.c (parse_output_constraint, parse_input_constraint): Likewise.
	* doc/tm.texi (CONSTRAINT_LEN, REG_CLASS_FROM_CONSTRAINT): Document.
	(CONST_OK_FOR_CONSTRAINT_P): Likewise.
	(CONST_DOUBLE_OK_FOR_CONSTRAINT_P, EXTRA_CONSTRAINT_STR): Likewise.
	(EXTRA_MEMORY_CONSTRAINT, EXTRA_ADDRESS_CONSTRAINT): Add STR argument.
	* config/s390/s390.h (EXTRA_MEMORY_CONSTRAINT): Likewise.

Index: defaults.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/defaults.h,v
retrieving revision 1.98
diff -p -u -r1.98 defaults.h
--- defaults.h	16 Dec 2002 18:19:20 -0000	1.98
+++ defaults.h	7 Jan 2003 18:51:41 -0000
@@ -604,13 +604,38 @@ You Lose!  You must define PREFERRED_DEB
 /* Determine whether extra constraint letter should be handled
    via address reload (like 'o').  */
 #ifndef EXTRA_MEMORY_CONSTRAINT
-#define EXTRA_MEMORY_CONSTRAINT(C) 0
+#define EXTRA_MEMORY_CONSTRAINT(C,STR) 0
 #endif
 
 /* Determine whether extra constraint letter should be handled
    as an address (like 'p').  */
 #ifndef EXTRA_ADDRESS_CONSTRAINT
-#define EXTRA_ADDRESS_CONSTRAINT(C) 0
+#define EXTRA_ADDRESS_CONSTRAINT(C,STR) 0
+#endif
+
+/* When a port defines CONSTRAINT_LEN, it should use DEFAULT_CONSTRAINT_LEN
+   for all the characters that it does not want to change, so things like the
+  'length' of a digit in a matching constraint is an implementation detail,
+   and not part of the interface.  */
+#define DEFAULT_CONSTRAINT_LEN(C,STR) 1
+
+#ifndef CONSTRAINT_LEN
+#define CONSTRAINT_LEN(C,STR) DEFAULT_CONSTRAINT_LEN (C, STR)
+#endif
+
+#if defined (CONST_OK_FOR_LETTER_P) && ! defined (CONST_OK_FOR_CONSTRAINT_P)
+#define CONST_OK_FOR_CONSTRAINT_P(VAL,C,STR) CONST_OK_FOR_LETTER_P (VAL, C)
+#endif
+
+#if defined (CONST_DOUBLE_OK_FOR_LETTER_P) && ! defined (CONST_DOUBLE_OK_FOR_CONSTRAINT_P)
+#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(OP,C,STR) \
+  CONST_DOUBLE_OK_FOR_LETTER_P (OP, C)
+#endif
+
+#define REG_CLASS_FROM_CONSTRAINT(C,STR) REG_CLASS_FROM_LETTER (C)
+
+#if defined (EXTRA_CONSTRAINT) && ! defined (EXTRA_CONSTRAINT_STR)
+#define EXTRA_CONSTRAINT_STR(OP, C,STR) EXTRA_CONSTRAINT (OP, C)
 #endif
 
 #endif  /* ! GCC_DEFAULTS_H */
Index: genoutput.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genoutput.c,v
retrieving revision 1.71
diff -p -u -r1.71 genoutput.c
--- genoutput.c	16 Dec 2002 18:19:35 -0000	1.71
+++ genoutput.c	7 Jan 2003 18:51:41 -0000
@@ -189,6 +189,8 @@ static void gen_insn PARAMS ((rtx, int))
 static void gen_peephole PARAMS ((rtx, int));
 static void gen_expand PARAMS ((rtx, int));
 static void gen_split PARAMS ((rtx, int));
+static void check_constraint_len PARAMS ((void));
+static int constraint_len PARAMS ((const char *, int));
 
 const char *
 get_insn_name (index)
@@ -749,7 +751,51 @@ validate_insn_alternatives (d)
   for (start = 0; start < d->n_operands; start++)
     if (d->operand[start].n_alternatives > 0)
       {
-	if (n == 0)
+	int len, i;
+	const char *p;
+	char c;
+	int which_alternative = 0;
+	int alternative_count_unsure = 0;
+
+	for (p = d->operand[start].constraint; (c = *p); p += len)
+	  {
+	    len = CONSTRAINT_LEN (c, p);
+
+	    if (len < 1 || (len > 1 && strchr (",#*+=&%!0123456789", c)))
+	      {
+		message_with_line (d->lineno,
+				   "invalid length %d for char '%c' in alternative %d of operand %d",
+				    len, c, which_alternative, start);
+		len = 1;
+		have_error = 1;
+	      }
+
+	    if (c == ',')
+	      {
+	        which_alternative++;
+		continue;
+	      }
+
+	    for (i = 1; i < len; i++)
+	      if (p[i] == '\0')
+		{
+		  message_with_line (d->lineno,
+				     "NUL in alternative %d of operand %d",
+				     which_alternative, start);
+		  alternative_count_unsure = 1;
+		  break;
+		}
+	      else if (strchr (",#*", p[i]))
+		{
+		  message_with_line (d->lineno,
+				     "'%c' in alternative %d of operand %d",
+				     p[i], which_alternative, start);
+		  alternative_count_unsure = 1;
+		}
+	  }
+	if (alternative_count_unsure)
+	  have_error = 1;
+	else if (n == 0)
 	  n = d->operand[start].n_alternatives;
 	else if (n != d->operand[start].n_alternatives)
 	  {
@@ -816,6 +862,7 @@ gen_insn (insn, lineno)
   d->n_operands = max_opno + 1;
   d->n_dups = num_dups;
 
+  check_constraint_len ();
   validate_insn_operands (d);
   validate_insn_alternatives (d);
   place_operands (d);
@@ -1042,4 +1089,42 @@ strip_whitespace (s)
 
   *p = '\0';
   return q;
+}
+
+/* Verify that DEFAULT_CONSTRAINT_LEN is used properly and not
+   tampered with.  This isn't bullet-proof, but it should catch
+   most genuine mistakes.  */
+static void
+check_constraint_len ()
+{
+  const char *p;
+  int d;
+
+  for (p = ",#*+=&%!1234567890"; *p; p++)
+    for (d = -9; d < 9; d++)
+      if (constraint_len (p, d) != d)
+	abort ();
+}
+
+static int
+constraint_len (p, genoutput_default_constraint_len)
+     const char *p;
+     int genoutput_default_constraint_len;
+{
+  /* Check that we still match defaults.h .  First we do a generation-time
+     check that fails if the value is not the expected one...  */
+  if (DEFAULT_CONSTRAINT_LEN (*p, p) != 1)
+    abort ();
+  /* And now a comile-time check that should give a diagnostic if the
+     definition doesn't exactly match.  */
+#define DEFAULT_CONSTRAINT_LEN(C,STR) 1
+  /* Now re-define DEFAULT_CONSTRAINT_LEN so that we can verify it is
+     being used.  */
+#undef DEFAULT_CONSTRAINT_LEN
+#define DEFAULT_CONSTRAINT_LEN(C,STR) \
+  ((C) != *p || STR != p ? -1 : genoutput_default_constraint_len)
+  return CONSTRAINT_LEN (*p, p);
+  /* And set it back.  */
+#undef DEFAULT_CONSTRAINT_LEN
+#define DEFAULT_CONSTRAINT_LEN(C,STR) 1
 }
Index: local-alloc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/local-alloc.c,v
retrieving revision 1.113
diff -p -u -r1.113 local-alloc.c
--- local-alloc.c	16 Dec 2002 18:19:42 -0000	1.113
+++ local-alloc.c	7 Jan 2003 18:51:42 -0000
@@ -1338,7 +1338,8 @@ block_alloc (b)
 		     There may be more than one register, but we only try one
 		     of them.  */
 		  if (recog_data.constraints[i][0] == 'p'
-		      || EXTRA_ADDRESS_CONSTRAINT (recog_data.constraints[i][0]))
+		      || EXTRA_ADDRESS_CONSTRAINT (recog_data.constraints[i][0],
+						   recog_data.constraints[i]))
 		    while (GET_CODE (r1) == PLUS || GET_CODE (r1) == MULT)
 		      r1 = XEXP (r1, 0);
 
@@ -2424,50 +2425,56 @@ requires_inout (p)
   int found_zero = 0;
   int reg_allowed = 0;
   int num_matching_alts = 0;
+  int len;
 
-  while ((c = *p++))
-    switch (c)
-      {
-      case '=':  case '+':  case '?':
-      case '#':  case '&':  case '!':
-      case '*':  case '%':
-      case 'm':  case '<':  case '>':  case 'V':  case 'o':
-      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':
-      case 'X':
-	/* These don't say anything we care about.  */
-	break;
+  for ( ; c = *p; p += len)
+    {
+      len = CONSTRAINT_LEN (c, p);
+      switch (c)
+	{
+	case '=':  case '+':  case '?':
+	case '#':  case '&':  case '!':
+	case '*':  case '%':
+	case 'm':  case '<':  case '>':  case 'V':  case 'o':
+	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':
+	case 'X':
+	  /* These don't say anything we care about.  */
+	  break;
 
-      case ',':
-	if (found_zero && ! reg_allowed)
-	  num_matching_alts++;
+	case ',':
+	  if (found_zero && ! reg_allowed)
+	    num_matching_alts++;
 
-	found_zero = reg_allowed = 0;
-	break;
+	  found_zero = reg_allowed = 0;
+	  break;
 
-      case '0':
-	found_zero = 1;
-	break;
+	case '0':
+	  found_zero = 1;
+	  break;
 
-      case '1':  case '2':  case '3':  case '4': case '5':
-      case '6':  case '7':  case '8':  case '9':
-	/* Skip the balance of the matching constraint.  */
-	while (ISDIGIT (*p))
-	  p++;
-	break;
+	case '1':  case '2':  case '3':  case '4': case '5':
+	case '6':  case '7':  case '8':  case '9':
+	  /* Skip the balance of the matching constraint.  */
+	  do
+	    p++;
+	  while (ISDIGIT (*p));
+	  len = 0;
+	  break;
 
-      default:
-	if (REG_CLASS_FROM_LETTER (c) == NO_REGS
-	    && !EXTRA_ADDRESS_CONSTRAINT (c))
+	default:
+	  if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS
+	      && !EXTRA_ADDRESS_CONSTRAINT (c, p))
+	    break;
+	  /* FALLTHRU */
+	case 'p':
+	case 'g': case 'r':
+	  reg_allowed = 1;
 	  break;
-	/* FALLTHRU */
-      case 'p':
-      case 'g': case 'r':
-	reg_allowed = 1;
-	break;
-      }
+	}
+    }
 
   if (found_zero && ! reg_allowed)
     num_matching_alts++;
Index: ra-build.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ra-build.c,v
retrieving revision 1.10
diff -p -u -r1.10 ra-build.c
--- ra-build.c	16 Dec 2002 18:19:47 -0000	1.10
+++ ra-build.c	7 Jan 2003 18:51:42 -0000
@@ -2933,13 +2933,13 @@ handle_asm_insn (df, insn)
       CLEAR_HARD_REG_SET (allowed);
       while (1)
 	{
-	  char c = *p++;
+	  char c = *p;
 
 	  if (c == '\0' || c == ',' || c == '#')
 	    {
 	      /* End of one alternative - mark the regs in the current
-	       class, and reset the class.
-	       */
+	       class, and reset the class.  */
+	      p++;
 	      IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
 	      if (cls != NO_REGS)
 		nothing_allowed = 0;
@@ -2977,8 +2977,10 @@ handle_asm_insn (df, insn)
 	      default:
 		cls =
 		  (int) reg_class_subunion[cls][(int)
-						REG_CLASS_FROM_LETTER (c)];
+						REG_CLASS_FROM_CONSTRAINT (c,
+									   p)];
 	    }
+	  p += CONSTRAINT_LEN (c, p);
 	}
 
       /* Now make conflicts between this web, and all hardregs, which
Index: recog.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/recog.c,v
retrieving revision 1.169
diff -p -u -r1.169 recog.c
--- recog.c	16 Dec 2002 18:19:49 -0000	1.169
+++ recog.c	7 Jan 2003 18:51:42 -0000
@@ -1681,18 +1681,21 @@ asm_operand_ok (op, constraint)
 
   while (*constraint)
     {
-      char c = *constraint++;
+      char c = *constraint;
+      int len;
       switch (c)
 	{
+	case ',':
+	  constraint++;
+	  continue;
 	case '=':
 	case '+':
 	case '*':
 	case '%':
-	case '?':
 	case '!':
 	case '#':
 	case '&':
-	case ',':
+	case '?':
 	  break;
 
 	case '0': case '1': case '2': case '3': case '4':
@@ -1701,25 +1704,27 @@ asm_operand_ok (op, constraint)
 	     proper matching constraint, but we can't actually fail
 	     the check if they didn't.  Indicate that results are
 	     inconclusive.  */
-	  while (ISDIGIT (*constraint))
+	  do
 	    constraint++;
-	  result = -1;
-	  break;
+	  while (ISDIGIT (*constraint));
+	  if (! result)
+	    result = -1;
+	  continue;
 
 	case 'p':
 	  if (address_operand (op, VOIDmode))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case 'm':
 	case 'V': /* non-offsettable */
 	  if (memory_operand (op, VOIDmode))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case 'o': /* offsettable */
 	  if (offsettable_nonstrict_memref_p (op))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case '<':
@@ -1734,7 +1739,7 @@ asm_operand_ok (op, constraint)
 	      && (1
 		  || GET_CODE (XEXP (op, 0)) == PRE_DEC
 		  || GET_CODE (XEXP (op, 0)) == POST_DEC))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case '>':
@@ -1742,7 +1747,7 @@ asm_operand_ok (op, constraint)
 	      && (1
 		  || GET_CODE (XEXP (op, 0)) == PRE_INC
 		  || GET_CODE (XEXP (op, 0)) == POST_INC))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case 'E':
@@ -1750,18 +1755,18 @@ asm_operand_ok (op, constraint)
 	  if (GET_CODE (op) == CONST_DOUBLE
 	      || (GET_CODE (op) == CONST_VECTOR
 		  && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case 'G':
 	  if (GET_CODE (op) == CONST_DOUBLE
-	      && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'G'))
-	    return 1;
+	      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', constraint))
+	    result = 1;
 	  break;
 	case 'H':
 	  if (GET_CODE (op) == CONST_DOUBLE
-	      && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'H'))
-	    return 1;
+	      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'H', constraint))
+	    result = 1;
 	  break;
 
 	case 's':
@@ -1777,94 +1782,100 @@ asm_operand_ok (op, constraint)
 	      && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
 	      )
-	    return 1;
+	    result = 1;
 	  break;
 
 	case 'n':
 	  if (GET_CODE (op) == CONST_INT
 	      || (GET_CODE (op) == CONST_DOUBLE
 		  && GET_MODE (op) == VOIDmode))
-	    return 1;
+	    result = 1;
 	  break;
 
 	case 'I':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
+	    result = 1;
 	  break;
 	case 'J':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'J'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
+	    result = 1;
 	  break;
 	case 'K':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
+	    result = 1;
 	  break;
 	case 'L':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
+	    result = 1;
 	  break;
 	case 'M':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
+	    result = 1;
 	  break;
 	case 'N':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'N'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
+	    result = 1;
 	  break;
 	case 'O':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
+	    result = 1;
 	  break;
 	case 'P':
 	  if (GET_CODE (op) == CONST_INT
-	      && CONST_OK_FOR_LETTER_P (INTVAL (op), 'P'))
-	    return 1;
+	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
+	    result = 1;
 	  break;
 
 	case 'X':
-	  return 1;
+	  result = 1;
 
 	case 'g':
 	  if (general_operand (op, VOIDmode))
-	    return 1;
+	    result = 1;
 	  break;
 
 	default:
 	  /* For all other letters, we first check for a register class,
 	     otherwise it is an EXTRA_CONSTRAINT.  */
-	  if (REG_CLASS_FROM_LETTER (c) != NO_REGS)
+	  if (REG_CLASS_FROM_CONSTRAINT (c, constraint) != NO_REGS)
 	    {
 	    case 'r':
 	      if (GET_MODE (op) == BLKmode)
 		break;
 	      if (register_operand (op, VOIDmode))
-		return 1;
+		result = 1;
 	    }
-#ifdef EXTRA_CONSTRAINT
-	  if (EXTRA_CONSTRAINT (op, c))
-	    return 1;
-	  if (EXTRA_MEMORY_CONSTRAINT (c))
+#ifdef EXTRA_CONSTRAINT_STR
+	  if (EXTRA_CONSTRAINT_STR (op, c, constraint))
+	    result = 1;
+	  if (EXTRA_MEMORY_CONSTRAINT (c, constraint))
 	    {
 	      /* Every memory operand can be reloaded to fit.  */
 	      if (memory_operand (op, VOIDmode))
-	        return 1;
+	        result = 1;
 	    }
-	  if (EXTRA_ADDRESS_CONSTRAINT (c))
+	  if (EXTRA_ADDRESS_CONSTRAINT (c, constraint))
 	    {
 	      /* Every address operand can be reloaded to fit.  */
 	      if (address_operand (op, VOIDmode))
-	        return 1;
+	        result = 1;
 	    }
 #endif
 	  break;
 	}
+      len = CONSTRAINT_LEN (c, constraint);
+      do
+	constraint++;
+      while (--len && *constraint);
+      if (len)
+	return 0;
     }
 
   return result;
@@ -2233,13 +2244,16 @@ preprocess_constraints ()
 
 	  for (;;)
 	    {
-	      char c = *p++;
+	      char c = *p;
 	      if (c == '#')
 		do
-		  c = *p++;
+		  c = *++p;
 		while (c != ',' && c != '\0');
 	      if (c == ',' || c == '\0')
-		break;
+		{
+		  p++;
+		  break;
+		}
 
 	      switch (c)
 		{
@@ -2265,11 +2279,11 @@ preprocess_constraints ()
 		case '5': case '6': case '7': case '8': case '9':
 		  {
 		    char *end;
-		    op_alt[j].matches = strtoul (p - 1, &end, 10);
+		    op_alt[j].matches = strtoul (p, &end, 10);
 		    recog_op_alt[op_alt[j].matches][j].matched = i;
 		    p = end;
 		  }
-		  break;
+		  continue;
 
 		case 'm':
 		  op_alt[j].memory_ok = 1;
@@ -2301,22 +2315,28 @@ preprocess_constraints ()
 		  break;
 
 		default:
-		  if (EXTRA_MEMORY_CONSTRAINT (c))
+		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
 		    {
 		      op_alt[j].memory_ok = 1;
 		      break;
 		    }
-		  if (EXTRA_ADDRESS_CONSTRAINT (c))
+		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
 		    {
 		      op_alt[j].is_address = 1;
-		      op_alt[j].class = reg_class_subunion[(int) op_alt[j].class]
-		        [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		      op_alt[j].class
+			= (reg_class_subunion
+			   [(int) op_alt[j].class]
+			   [(int) MODE_BASE_REG_CLASS (VOIDmode)]);
 		      break;
 		    }
 
-		  op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
+		  op_alt[j].class
+		    = (reg_class_subunion
+		       [(int) op_alt[j].class]
+		       [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
 		  break;
 		}
+	      p += CONSTRAINT_LEN (c, p);
 	    }
 	}
     }
@@ -2331,7 +2351,7 @@ preprocess_constraints ()
    alternative of constraints was matched: 0 for the first alternative,
    1 for the next, etc.
 
-   In addition, when two operands are match
+   In addition, when two operands are required to match
    and it happens that the output operand is (reg) while the
    input operand is --(reg) or ++(reg) (a pre-inc or pre-dec),
    make the output operand look like the input.
@@ -2390,6 +2410,7 @@ constrain_operands (strict)
 	  int offset = 0;
 	  int win = 0;
 	  int val;
+	  int len;
 
 	  earlyclobber[opno] = 0;
 
@@ -2414,9 +2435,16 @@ constrain_operands (strict)
 	  if (*p == 0 || *p == ',')
 	    win = 1;
 
-	  while (*p && (c = *p++) != ',')
-	    switch (c)
+	  do
+	    switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
 	      {
+	      case '\0':
+		len = 0;
+		break;
+	      case ',':
+		c = '\0';
+		break;
+
 	      case '?':  case '!': case '*':  case '%':
 	      case '=':  case '+':
 		break;
@@ -2424,8 +2452,10 @@ constrain_operands (strict)
 	      case '#':
 		/* Ignore rest of this alternative as far as
 		   constraint checking is concerned.  */
-		while (*p && *p != ',')
+		do
 		  p++;
+		while (*p && *p != ',');
+		len = 0;
 		break;
 
 	      case '&':
@@ -2447,7 +2477,7 @@ constrain_operands (strict)
 		  char *end;
 		  int match;
 
-		  match = strtoul (p - 1, &end, 10);
+		  match = strtoul (p, &end, 10);
 		  p = end;
 
 		  if (strict < 0)
@@ -2482,6 +2512,7 @@ constrain_operands (strict)
 		      funny_match[funny_match_index++].other = match;
 		    }
 		}
+		len = 0;
 		break;
 
 	      case 'p':
@@ -2551,7 +2582,7 @@ constrain_operands (strict)
 	      case 'G':
 	      case 'H':
 		if (GET_CODE (op) == CONST_DOUBLE
-		    && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
+		    && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
 		  win = 1;
 		break;
 
@@ -2581,7 +2612,7 @@ constrain_operands (strict)
 	      case 'O':
 	      case 'P':
 		if (GET_CODE (op) == CONST_INT
-		    && CONST_OK_FOR_LETTER_P (INTVAL (op), c))
+		    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
 		  win = 1;
 		break;
 
@@ -2612,7 +2643,8 @@ constrain_operands (strict)
 		{
 		  enum reg_class class;
 
-		  class = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (c));
+		  class = (c == 'r'
+			   ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
 		  if (class != NO_REGS)
 		    {
 		      if (strict < 0
@@ -2624,11 +2656,11 @@ constrain_operands (strict)
 			      && reg_fits_class_p (op, class, offset, mode)))
 		        win = 1;
 		    }
-#ifdef EXTRA_CONSTRAINT
-		  else if (EXTRA_CONSTRAINT (op, c))
+#ifdef EXTRA_CONSTRAINT_STR
+		  else if (EXTRA_CONSTRAINT_STR (op, c, p))
 		    win = 1;
 
-		  if (EXTRA_MEMORY_CONSTRAINT (c))
+		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
 		    {
 		      /* Every memory operand can be reloaded to fit.  */
 		      if (strict < 0 && GET_CODE (op) == MEM)
@@ -2643,7 +2675,7 @@ constrain_operands (strict)
 			  && REGNO (op) >= FIRST_PSEUDO_REGISTER)
 			win = 1;
 		    }
-		  if (EXTRA_ADDRESS_CONSTRAINT (c))
+		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
 		    {
 		      /* Every address operand can be reloaded to fit.  */
 		      if (strict < 0)
@@ -2653,6 +2685,7 @@ constrain_operands (strict)
 		  break;
 		}
 	      }
+	  while (p += len, c);
 
 	  constraints[opno] = p;
 	  /* If this operand did not win somehow,
@@ -3009,7 +3042,7 @@ peep2_find_free_register (from, to, clas
     }
 
   class = (class_str[0] == 'r' ? GENERAL_REGS
-	   : REG_CLASS_FROM_LETTER (class_str[0]));
+	   : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
Index: regclass.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regclass.c,v
retrieving revision 1.161
diff -p -u -r1.161 regclass.c
--- regclass.c	16 Dec 2002 18:19:50 -0000	1.161
+++ regclass.c	7 Jan 2003 18:51:43 -0000
@@ -977,7 +977,7 @@ record_operand_costs (insn, op_costs, re
 	record_address_regs (XEXP (recog_data.operand[i], 0),
 			     MODE_BASE_REG_CLASS (modes[i]), frequency * 2);
       else if (constraints[i][0] == 'p'
-	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0]))
+	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
 	record_address_regs (recog_data.operand[i],
 			     MODE_BASE_REG_CLASS (modes[i]), frequency * 2);
     }
@@ -1548,154 +1548,161 @@ record_reg_classes (n_alts, n_ops, ops, 
 	     any of the constraints.  Collect the valid register classes
 	     and see if this operand accepts memory.  */
 
-	  while (*p && (c = *p++) != ',')
-	    switch (c)
-	      {
-	      case '*':
-		/* Ignore the next letter for this pass.  */
-		p++;
-		break;
-
-	      case '?':
-		alt_cost += 2;
-	      case '!':  case '#':  case '&':
-	      case '0':  case '1':  case '2':  case '3':  case '4':
-	      case '5':  case '6':  case '7':  case '8':  case '9':
-		break;
+	  while ((c = *p))
+	    {
+	      switch (c)
+		{
+		case ',':
+		  break;
+		case '*':
+		  /* Ignore the next letter for this pass.  */
+		  c = *++p;
+		  break;
 
-	      case 'p':
-		allows_addr = 1;
-		win = address_operand (op, GET_MODE (op));
-		/* We know this operand is an address, so we want it to be
-		   allocated to a register that can be the base of an
-		   address, ie BASE_REG_CLASS.  */
-		classes[i]
-		  = reg_class_subunion[(int) classes[i]]
-		    [(int) MODE_BASE_REG_CLASS (VOIDmode)];
-		break;
+		case '?':
+		  alt_cost += 2;
+		case '!':  case '#':  case '&':
+		case '0':  case '1':  case '2':  case '3':  case '4':
+		case '5':  case '6':  case '7':  case '8':  case '9':
+		  break;
 
-	      case 'm':  case 'o':  case 'V':
-		/* It doesn't seem worth distinguishing between offsettable
-		   and non-offsettable addresses here.  */
-		allows_mem[i] = 1;
-		if (GET_CODE (op) == MEM)
-		  win = 1;
-		break;
+		case 'p':
+		  allows_addr = 1;
+		  win = address_operand (op, GET_MODE (op));
+		  /* We know this operand is an address, so we want it to be
+		     allocated to a register that can be the base of an
+		     address, ie BASE_REG_CLASS.  */
+		  classes[i]
+		    = reg_class_subunion[(int) classes[i]]
+		      [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		  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 'm':  case 'o':  case 'V':
+		  /* It doesn't seem worth distinguishing between offsettable
+		     and non-offsettable addresses here.  */
+		  allows_mem[i] = 1;
+		  if (GET_CODE (op) == MEM)
+		    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 '<':
+		  if (GET_CODE (op) == MEM
+		      && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+			  || GET_CODE (XEXP (op, 0)) == POST_DEC))
+		    win = 1;
+		  break;
 
-	      case 'E':
-	      case 'F':
-		if (GET_CODE (op) == CONST_DOUBLE
-		    || (GET_CODE (op) == CONST_VECTOR
-			&& (GET_MODE_CLASS (GET_MODE (op))
-			    == MODE_VECTOR_FLOAT)))
-		  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 'G':
-	      case 'H':
-		if (GET_CODE (op) == CONST_DOUBLE
-		    && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
-		  win = 1;
-		break;
+		case 'E':
+		case 'F':
+		  if (GET_CODE (op) == CONST_DOUBLE
+		      || (GET_CODE (op) == CONST_VECTOR
+			  && (GET_MODE_CLASS (GET_MODE (op))
+			      == MODE_VECTOR_FLOAT)))
+		    win = 1;
+		  break;
 
-	      case 's':
-		if (GET_CODE (op) == CONST_INT
-		    || (GET_CODE (op) == CONST_DOUBLE
-			&& GET_MODE (op) == VOIDmode))
+		case 'G':
+		case 'H':
+		  if (GET_CODE (op) == CONST_DOUBLE
+		      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
+		    win = 1;
 		  break;
-	      case 'i':
-		if (CONSTANT_P (op)
+
+		case 's':
+		  if (GET_CODE (op) == CONST_INT
+		      || (GET_CODE (op) == CONST_DOUBLE
+			  && GET_MODE (op) == VOIDmode))
+		    break;
+		case 'i':
+		  if (CONSTANT_P (op)
 #ifdef LEGITIMATE_PIC_OPERAND_P
-		    && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
+		      && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
-		    )
-		  win = 1;
-		break;
+		      )
+		    win = 1;
+		  break;
 
-	      case 'n':
-		if (GET_CODE (op) == CONST_INT
-		    || (GET_CODE (op) == CONST_DOUBLE
-			&& GET_MODE (op) == VOIDmode))
-		  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;
+		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_CONSTRAINT_P (INTVAL (op), c, p))
+		    win = 1;
+		  break;
 
-	      case 'X':
-		win = 1;
-		break;
+		case 'X':
+		  win = 1;
+		  break;
 
-	      case 'g':
-		if (GET_CODE (op) == MEM
-		    || (CONSTANT_P (op)
+		case 'g':
+		  if (GET_CODE (op) == MEM
+		      || (CONSTANT_P (op)
 #ifdef LEGITIMATE_PIC_OPERAND_P
-			&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
+			  && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
-			))
-		  win = 1;
-		allows_mem[i] = 1;
-	      case 'r':
-		classes[i]
-		  = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS];
-		break;
-
-	      default:
-		if (REG_CLASS_FROM_LETTER (c) != NO_REGS)
+			  ))
+		    win = 1;
+		  allows_mem[i] = 1;
+		case 'r':
 		  classes[i]
-		    = reg_class_subunion[(int) classes[i]]
-		      [(int) REG_CLASS_FROM_LETTER (c)];
-#ifdef EXTRA_CONSTRAINT
-		else if (EXTRA_CONSTRAINT (op, c))
-		  win = 1;
+		    = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS];
+		  break;
 
-		if (EXTRA_MEMORY_CONSTRAINT (c))
-		  {
-		    /* Every MEM can be reloaded to fit.  */
-		    allows_mem[i] = 1;
-		    if (GET_CODE (op) == MEM)
-		      win = 1;
-		  }
-		if (EXTRA_ADDRESS_CONSTRAINT (op))
-		  {
-		    /* Every address can be reloaded to fit.  */
-		    allows_addr = 1;
-		    if (address_operand (op, GET_MODE (op)))
-		      win = 1;
-		    /* We know this operand is an address, so we want it to be
-		       allocated to a register that can be the base of an
-		       address, ie BASE_REG_CLASS.  */
+		default:
+		  if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS)
 		    classes[i]
 		      = reg_class_subunion[(int) classes[i]]
-		        [(int) MODE_BASE_REG_CLASS (VOIDmode)];
-		  }
+			[(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
+#ifdef EXTRA_CONSTRAINT_STR
+		  else if (EXTRA_CONSTRAINT_STR (op, c, p))
+		    win = 1;
+
+		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
+		    {
+		      /* Every MEM can be reloaded to fit.  */
+		      allows_mem[i] = 1;
+		      if (GET_CODE (op) == MEM)
+			win = 1;
+		    }
+		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+		    {
+		      /* Every address can be reloaded to fit.  */
+		      allows_addr = 1;
+		      if (address_operand (op, GET_MODE (op)))
+			win = 1;
+		      /* We know this operand is an address, so we want it to
+			 be allocated to a register that can be the base of an
+			 address, ie BASE_REG_CLASS.  */
+		      classes[i]
+			= reg_class_subunion[(int) classes[i]]
+			  [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+		    }
 #endif
+		  break;
+		}
+	      p += CONSTRAINT_LEN (c, p);
+	      if (c == ',')
 		break;
-	      }
+	    }
 
 	  constraints[i] = p;
 
Index: regmove.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/regmove.c,v
retrieving revision 1.135
diff -p -u -r1.135 regmove.c
--- regmove.c	16 Dec 2002 18:19:50 -0000	1.135
+++ regmove.c	7 Jan 2003 18:51:43 -0000
@@ -1570,47 +1570,50 @@ find_matches (insn, matchp)
 	if (*p == ',')
 	  i++;
 
-      while ((c = *p++) != '\0' && c != ',')
-	switch (c)
-	  {
-	  case '=':
-	    break;
-	  case '+':
-	    break;
-	  case '&':
-	    matchp->early_clobber[op_no] = 1;
-	    break;
-	  case '%':
-	    matchp->commutative[op_no] = op_no + 1;
-	    matchp->commutative[op_no + 1] = op_no;
-	    break;
-
-	  case '0': case '1': case '2': case '3': case '4':
-	  case '5': case '6': case '7': case '8': case '9':
+      while ((c = *p) != '\0' && c != ',')
+	{
+	  switch (c)
 	    {
-	      char *end;
-	      unsigned long match_ul = strtoul (p - 1, &end, 10);
-	      int match = match_ul;
+	    case '=':
+	      break;
+	    case '+':
+	      break;
+	    case '&':
+	      matchp->early_clobber[op_no] = 1;
+	      break;
+	    case '%':
+	      matchp->commutative[op_no] = op_no + 1;
+	      matchp->commutative[op_no + 1] = op_no;
+	      break;
 
-	      p = end;
+	    case '0': case '1': case '2': case '3': case '4':
+	    case '5': case '6': case '7': case '8': case '9':
+	      {
+		char *end;
+		unsigned long match_ul = strtoul (p, &end, 10);
+		int match = match_ul;
 
-	      if (match < op_no && likely_spilled[match])
-		break;
-	      matchp->with[op_no] = match;
-	      any_matches = 1;
-	      if (matchp->commutative[op_no] >= 0)
-		matchp->with[matchp->commutative[op_no]] = match;
-	    }
-	    break;
+		p = end;
+
+		if (match < op_no && likely_spilled[match])
+		  continue;
+		matchp->with[op_no] = match;
+		any_matches = 1;
+		if (matchp->commutative[op_no] >= 0)
+		  matchp->with[matchp->commutative[op_no]] = match;
+	      }
+	    continue;
 
 	  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
 	  case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
 	  case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
 	  case 'C': case 'D': case 'W': case 'Y': case 'Z':
-	    if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER ((unsigned char) c)))
+	    if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p) ))
 	      likely_spilled[op_no] = 1;
 	    break;
 	  }
+	  p += CONSTRAINT_LEN (c, p);
+	}
     }
   return any_matches;
 }
Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.200
diff -p -u -r1.200 reload.c
--- reload.c	16 Dec 2002 18:19:50 -0000	1.200
+++ reload.c	7 Jan 2003 18:51:44 -0000
@@ -381,11 +381,13 @@ push_secondary_reload (in_p, x, opnum, o
 	insn_class = ALL_REGS;
       else
 	{
-	  char insn_letter
-	    = insn_data[(int) icode].operand[!in_p].constraint[in_p];
+	  const char *insn_constraint
+	    = &insn_data[(int) icode].operand[!in_p].constraint[in_p];
+	  char insn_letter = *insn_constraint;
 	  insn_class
 	    = (insn_letter == 'r' ? GENERAL_REGS
-	       : REG_CLASS_FROM_LETTER ((unsigned char) insn_letter));
+	       : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
+					    insn_constraint));
 
           if (insn_class == NO_REGS)
 	    abort ();
@@ -403,11 +405,14 @@ push_secondary_reload (in_p, x, opnum, o
 	mode = insn_data[(int) icode].operand[2].mode;
       else
 	{
-	  char t_letter = insn_data[(int) icode].operand[2].constraint[2];
+	  const char *t_constraint
+	    = &insn_data[(int) icode].operand[2].constraint[2];
+	  char t_letter = *t_constraint;
 	  class = insn_class;
 	  t_mode = insn_data[(int) icode].operand[2].mode;
 	  t_class = (t_letter == 'r' ? GENERAL_REGS
-		     : REG_CLASS_FROM_LETTER ((unsigned char) t_letter));
+		     : REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter,
+						  t_constraint));
 	  t_icode = icode;
 	  icode = CODE_FOR_nothing;
 	}
@@ -2587,8 +2592,9 @@ find_reloads (insn, replace, ind_levels,
       /* Scan this operand's constraint to see if it is an output operand,
 	 an in-out operand, is commutative, or should match another.  */
 
-      while ((c = *p++))
+      while ((c = *p))
 	{
+	  p += CONSTRAINT_LEN (c, p);
 	  if (c == '=')
 	    modified[i] = RELOAD_WRITE;
 	  else if (c == '+')
@@ -2664,7 +2670,7 @@ find_reloads (insn, replace, ind_levels,
 	/* Ignore things like match_operator operands.  */
 	;
       else if (constraints[i][0] == 'p'
-	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0]))
+	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
 	{
 	  find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
 				recog_data.operand[i],
@@ -2829,6 +2835,8 @@ find_reloads (insn, replace, ind_levels,
       for (i = 0; i < noperands; i++)
 	{
 	  char *p = constraints[i];
+	  char *end;
+	  int len;
 	  int win = 0;
 	  int did_match = 0;
 	  /* 0 => this operand can be reloaded somehow for this alternative.  */
@@ -2836,6 +2844,7 @@ find_reloads (insn, replace, ind_levels,
 	  /* 0 => this operand can be reloaded if the alternative allows regs.  */
 	  int winreg = 0;
 	  int c;
+	  int m;
 	  rtx operand = recog_data.operand[i];
 	  int offset = 0;
 	  /* Nonzero means this is a MEM that must be reloaded into a reg
@@ -2964,9 +2973,16 @@ find_reloads (insn, replace, ind_levels,
 	     or set WINREG if this operand could fit after reloads
 	     provided the constraint allows some registers.  */
 
-	  while (*p && (c = *p++) != ',')
-	    switch (c)
+	  do
+	    switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
 	      {
+	      case '\0':
+		len = 0;
+		break;
+	      case ',':
+		c = '\0';
+		break;
+
 	      case '=':  case '+':  case '*':
 		break;
 
@@ -2987,15 +3003,19 @@ find_reloads (insn, replace, ind_levels,
 	      case '#':
 		/* Ignore rest of this alternative as far as
 		   reloading is concerned.  */
-		while (*p && *p != ',')
+		do
 		  p++;
+		while (*p && *p != ',');
+		len = 0;
 		break;
 
 	      case '0':  case '1':  case '2':  case '3':  case '4':
 	      case '5':  case '6':  case '7':  case '8':  case '9':
-		c = strtoul (p - 1, &p, 10);
+		m = strtoul (p, &end, 10);
+		p = end;
+		len = 0;
 
-		this_alternative_matches[i] = c;
+		this_alternative_matches[i] = m;
 		/* We are supposed to match a previous operand.
 		   If we do, we win if that one did.
 		   If we do not, count both of the operands as losers.
@@ -3003,7 +3023,7 @@ find_reloads (insn, replace, ind_levels,
 		   only a single reload insn will be needed to make
 		   the two operands win.  As a result, this alternative
 		   may be rejected when it is actually desirable.)  */
-		if ((swapped && (c != commutative || i != commutative + 1))
+		if ((swapped && (m != commutative || i != commutative + 1))
 		    /* If we are matching as if two operands were swapped,
 		       also pretend that operands_match had been computed
 		       with swapped.
@@ -3011,22 +3031,22 @@ find_reloads (insn, replace, ind_levels,
 		       don't exchange them, because operands_match is valid
 		       only on one side of its diagonal.  */
 		    ? (operands_match
-		       [(c == commutative || c == commutative + 1)
-		       ? 2 * commutative + 1 - c : c]
+		       [(m == commutative || m == commutative + 1)
+		       ? 2 * commutative + 1 - m : m]
 		       [(i == commutative || i == commutative + 1)
 		       ? 2 * commutative + 1 - i : i])
-		    : operands_match[c][i])
+		    : operands_match[m][i])
 		  {
 		    /* If we are matching a non-offsettable address where an
 		       offsettable address was expected, then we must reject
 		       this combination, because we can't reload it.  */
-		    if (this_alternative_offmemok[c]
-			&& GET_CODE (recog_data.operand[c]) == MEM
-			&& this_alternative[c] == (int) NO_REGS
-			&& ! this_alternative_win[c])
+		    if (this_alternative_offmemok[m]
+			&& GET_CODE (recog_data.operand[m]) == MEM
+			&& this_alternative[m] == (int) NO_REGS
+			&& ! this_alternative_win[m])
 		      bad = 1;
 
-		    did_match = this_alternative_win[c];
+		    did_match = this_alternative_win[m];
 		  }
 		else
 		  {
@@ -3034,21 +3054,21 @@ find_reloads (insn, replace, ind_levels,
 		    rtx value;
 		    /* Retroactively mark the operand we had to match
 		       as a loser, if it wasn't already.  */
-		    if (this_alternative_win[c])
+		    if (this_alternative_win[m])
 		      losers++;
-		    this_alternative_win[c] = 0;
-		    if (this_alternative[c] == (int) NO_REGS)
+		    this_alternative_win[m] = 0;
+		    if (this_alternative[m] == (int) NO_REGS)
 		      bad = 1;
 		    /* But count the pair only once in the total badness of
 		       this alternative, if the pair can be a dummy reload.  */
 		    value
 		      = find_dummy_reload (recog_data.operand[i],
-					   recog_data.operand[c],
+					   recog_data.operand[m],
 					   recog_data.operand_loc[i],
-					   recog_data.operand_loc[c],
-					   operand_mode[i], operand_mode[c],
-					   this_alternative[c], -1,
-					   this_alternative_earlyclobber[c]);
+					   recog_data.operand_loc[m],
+					   operand_mode[i], operand_mode[m],
+					   this_alternative[m], -1,
+					   this_alternative_earlyclobber[m]);
 
 		    if (value != 0)
 		      losers--;
@@ -3056,7 +3076,7 @@ find_reloads (insn, replace, ind_levels,
 		/* This can be fixed with reloads if the operand
 		   we are supposed to match can be fixed with reloads.  */
 		badop = 0;
-		this_alternative[i] = this_alternative[c];
+		this_alternative[i] = this_alternative[m];
 
 		/* If we have to reload this operand and some previous
 		   operand also had to match the same thing as this
@@ -3175,7 +3195,7 @@ find_reloads (insn, replace, ind_levels,
 	      case 'G':
 	      case 'H':
 		if (GET_CODE (operand) == CONST_DOUBLE
-		    && CONST_DOUBLE_OK_FOR_LETTER_P (operand, c))
+		    && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
 		  win = 1;
 		break;
 
@@ -3209,7 +3229,7 @@ find_reloads (insn, replace, ind_levels,
 	      case 'O':
 	      case 'P':
 		if (GET_CODE (operand) == CONST_INT
-		    && CONST_OK_FOR_LETTER_P (INTVAL (operand), c))
+		    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
 		  win = 1;
 		break;
 
@@ -3242,14 +3262,14 @@ find_reloads (insn, replace, ind_levels,
 		goto reg;
 
 	      default:
-		if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
+		if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
 		  {
-#ifdef EXTRA_CONSTRAINT
-		    if (EXTRA_MEMORY_CONSTRAINT (c))
+#ifdef EXTRA_CONSTRAINT_STR
+		    if (EXTRA_MEMORY_CONSTRAINT (c, p))
 		      {
 			if (force_reload)
 			  break;
-		        if (EXTRA_CONSTRAINT (operand, c))
+		        if (EXTRA_CONSTRAINT_STR (operand, c, p))
 		          win = 1;
 			/* If the address was already reloaded,
 			   we win as well.  */
@@ -3262,7 +3282,7 @@ find_reloads (insn, replace, ind_levels,
 			    && REGNO (operand) >= FIRST_PSEUDO_REGISTER
 			    && reg_renumber[REGNO (operand)] < 0
 			    && ((reg_equiv_mem[REGNO (operand)] != 0
-			         && EXTRA_CONSTRAINT (reg_equiv_mem[REGNO (operand)], c))
+			         && EXTRA_CONSTRAINT_STR (reg_equiv_mem[REGNO (operand)], c, p))
 			        || (reg_equiv_address[REGNO (operand)] != 0)))
 			  win = 1;
 
@@ -3276,9 +3296,9 @@ find_reloads (insn, replace, ind_levels,
 			offmemok = 1;
 			break;
 		      }
-		    if (EXTRA_ADDRESS_CONSTRAINT (c))
+		    if (EXTRA_ADDRESS_CONSTRAINT (c, p))
 		      {
-		        if (EXTRA_CONSTRAINT (operand, c))
+		        if (EXTRA_CONSTRAINT_STR (operand, c, p))
 		          win = 1;
 
 			/* If we didn't already win, we can reload
@@ -3292,14 +3312,16 @@ find_reloads (insn, replace, ind_levels,
 			break;
 		      }
 
-		    if (EXTRA_CONSTRAINT (operand, c))
+		    if (EXTRA_CONSTRAINT_STR (operand, c, p))
 		      win = 1;
 #endif
 		    break;
 		  }
 
 		this_alternative[i]
-		  = (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
+		  = (int) (reg_class_subunion
+			   [this_alternative[i]]
+			   [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
 	      reg:
 		if (GET_MODE (operand) == BLKmode)
 		  break;
@@ -3310,6 +3332,7 @@ find_reloads (insn, replace, ind_levels,
 		  win = 1;
 		break;
 	      }
+	  while ((p += len), c);
 
 	  constraints[i] = p;
 
@@ -4358,8 +4381,9 @@ alternative_allows_memconst (constraint,
     }
   /* Scan the requested alternative for 'm' or 'o'.
      If one of them is present, this alternative accepts memory constants.  */
-  while ((c = *constraint++) && c != ',' && c != '#')
-    if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c))
+  for (; (c = *constraint) && c != ',' && c != '#';
+       constraint += CONSTRAINT_LEN (c, constraint))
+    if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint))
       return 1;
   return 0;
 }
Index: reload1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload1.c,v
retrieving revision 1.368
diff -p -u -r1.368 reload1.c
--- reload1.c	19 Dec 2002 05:18:05 -0000	1.368
+++ reload1.c	7 Jan 2003 18:51:44 -0000
@@ -1355,7 +1355,7 @@ maybe_fix_stack_asms ()
 
 	  for (;;)
 	    {
-	      char c = *p++;
+	      char c = *p;
 
 	      if (c == '\0' || c == ',' || c == '#')
 		{
@@ -1363,6 +1363,7 @@ maybe_fix_stack_asms ()
 		     class, and reset the class.  */
 		  IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
 		  cls = NO_REGS;
+		  p++;
 		  if (c == '#')
 		    do {
 		      c = *p++;
@@ -1393,13 +1394,14 @@ maybe_fix_stack_asms ()
 		  break;
 
 		default:
-		  if (EXTRA_ADDRESS_CONSTRAINT (c))
+		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
 		    cls = (int) reg_class_subunion[cls]
 		      [(int) MODE_BASE_REG_CLASS (VOIDmode)];
 		  else
 		    cls = (int) reg_class_subunion[cls]
-		      [(int) REG_CLASS_FROM_LETTER (c)];
+		      [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
 		}
+	      p += CONSTRAINT_LEN (c, p);
 	    }
 	}
       /* Those of the registers which are clobbered, but allowed by the
@@ -8413,7 +8415,7 @@ reload_cse_simplify_operands (insn, test
 	  p = constraints[i];
 	  for (;;)
 	    {
-	      char c = *p++;
+	      char c = *p;
 
 	      switch (c)
 		{
@@ -8437,7 +8439,9 @@ reload_cse_simplify_operands (insn, test
 
 		default:
 		  class
-		    = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
+		    = (reg_class_subunion
+		       [(int) class]
+		       [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
 		  break;
 
 		case ',': case '\0':
@@ -8457,6 +8461,7 @@ reload_cse_simplify_operands (insn, test
 		  j++;
 		  break;
 		}
+	      p += CONSTRAINT_LEN (c, p);
 
 	      if (c == '\0')
 		break;
Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.279
diff -p -u -r1.279 stmt.c
--- stmt.c	19 Dec 2002 17:06:45 -0000	1.279
+++ stmt.c	7 Jan 2003 18:51:46 -0000
@@ -1189,7 +1189,7 @@ parse_output_constraint (constraint_p, o
     }
 
   /* Loop through the constraint string.  */
-  for (p = constraint + 1; *p; ++p)
+  for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
     switch (*p)
       {
       case '+':
@@ -1241,12 +1241,12 @@ parse_output_constraint (constraint_p, o
       default:
 	if (!ISALPHA (*p))
 	  break;
-	if (REG_CLASS_FROM_LETTER (*p) != NO_REGS)
+	if (REG_CLASS_FROM_CONSTRAINT (*p, p) != NO_REGS)
 	  *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT
-	else if (EXTRA_ADDRESS_CONSTRAINT (*p))
+#ifdef EXTRA_CONSTRAINT_STR
+	else if (EXTRA_ADDRESS_CONSTRAINT (*p, p))
 	  *allows_reg = true;
-	else if (EXTRA_MEMORY_CONSTRAINT (*p))
+	else if (EXTRA_MEMORY_CONSTRAINT (*p, p))
 	  *allows_mem = true;
 	else
 	  {
@@ -1289,7 +1289,7 @@ parse_input_constraint (constraint_p, in
 
   /* Make sure constraint has neither `=', `+', nor '&'.  */
 
-  for (j = 0; j < c_len; j++)
+  for (j = 0; j < c_len; j += CONSTRAINT_LEN (constraint[j], constraint+j))
     switch (constraint[j])
       {
       case '+':  case '=':  case '&':
@@ -1348,10 +1348,16 @@ parse_input_constraint (constraint_p, in
 	      *constraint_p = constraint;
 	      c_len = strlen (constraint);
 	      j = 0;
+	      /* ??? At the end of the loop, we will skip the first part of
+		 the matched constraint.  This assumes not only that the
+		 other constraint is an output constraint, but also that
+		 the '=' or '+' come first.  */
 	      break;
 	    }
 	  else
 	    j = end - constraint;
+	  /* Anticipate increment at end of loop.  */
+	  j--;
 	}
 	/* Fall through.  */
 
@@ -1370,12 +1376,13 @@ parse_input_constraint (constraint_p, in
 	    error ("invalid punctuation `%c' in constraint", constraint[j]);
 	    return false;
 	  }
-	if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
+	if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
+	    != NO_REGS)
 	  *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT
-	else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j]))
+#ifdef EXTRA_CONSTRAINT_STR
+	else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j], constraint + j))
 	  *allows_reg = true;
-	else if (EXTRA_MEMORY_CONSTRAINT (constraint[j]))
+	else if (EXTRA_MEMORY_CONSTRAINT (constraint[j], constraint + j))
 	  *allows_mem = true;
 	else
 	  {
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.184
diff -p -u -r1.184 tm.texi
--- doc/tm.texi	17 Dec 2002 16:47:45 -0000	1.184
+++ doc/tm.texi	7 Jan 2003 18:51:50 -0000
@@ -1908,7 +1908,8 @@ If the usage of an entire class of regis
 flags, you may indicate this to GCC by using this macro to modify
 @code{fixed_regs} and @code{call_used_regs} to 1 for each of the
 registers in the classes which should not be used by GCC@.  Also define
-the macro @code{REG_CLASS_FROM_LETTER} to return @code{NO_REGS} if it
+the macro @code{REG_CLASS_FROM_LETTER} / @code{REG_CLASS_FROM_CONSTRAINT}
+to return @code{NO_REGS} if it
 is called with a letter for a class that shouldn't be used.
 
 (However, if this class is not included in @code{GENERAL_REGS} and all
@@ -2328,6 +2329,21 @@ index register must belong.  An index re
 address where its value is either multiplied by a scale factor or
 added to another register (as well as added to a displacement).
 
+@findex CONSTRAINT_LEN
+@item CONSTRAINT_LEN (@var{char}, @var{str})
+For the constraint at the start of @var{str}, which starts with the letter
+@var{c}, return the length.  This allows you to have register class /
+constant / extra constraints that are longer than a single letter;
+you don't need to define this macro if you can do with single-letter
+constraints only.  The definition of this macro should use
+DEFAULT_CONSTRAINT_LEN for all the characters that you don't want
+to handle specially.
+There are some sanity checks in genoutput.c that check the constraint lengths
+for the md file, so you can also use this macro to help you while you are
+transitioning from a byzantine single-letter-constraint scheme: when you
+return a negative length for a constraint you want to re-use, genoutput
+will complain about every instance where it is used in the md file.
+
 @findex REG_CLASS_FROM_LETTER
 @item REG_CLASS_FROM_LETTER (@var{char})
 A C expression which defines the machine-dependent operand constraint
@@ -2337,6 +2353,12 @@ the value should be @code{NO_REGS}.  The
 corresponding to class @code{GENERAL_REGS}, will not be passed
 to this macro; you do not need to handle it.
 
+@findex REG_CLASS_FROM_CONSTRAINT
+@item REG_CLASS_FROM_CONSTRAINT (@var{char}, @var{str})
+Like @code{REG_CLASS_FROM_LETTER}, but you also get the constraint string
+passed in @var{str}, so that you can use suffixes to distinguish between
+different variants.
+
 @findex REGNO_OK_FOR_BASE_P
 @item REGNO_OK_FOR_BASE_P (@var{num})
 A C expression which is nonzero if register number @var{num} is
@@ -2606,6 +2628,12 @@ the appropriate range and return 1 if so
 not one of those letters, the value should be 0 regardless of
 @var{value}.
 
+@findex CONST_OK_FOR_CONSTRAINT_P
+@item CONST_OK_FOR_CONSTRAINT_P (@var{value}, @var{c}, @var{str})
+Like @code{CONST_OK_FOR_LETTER_P}, but you also get the constraint
+string passed in @var{str}, so that you can use suffixes to distinguish
+between different variants.
+
 @findex CONST_DOUBLE_OK_FOR_LETTER_P
 @item CONST_DOUBLE_OK_FOR_LETTER_P (@var{value}, @var{c})
 A C expression that defines the machine-dependent operand constraint
@@ -2622,12 +2650,19 @@ letters, the value should be 0 regardles
 or both kinds of values.  It can use @code{GET_MODE} to distinguish
 between these kinds.
 
+@findex CONST_DOUBLE_OK_FOR_CONSTRAINT_P
+@item CONST_DOUBLE_OK_FOR_CONSTRAINT_P (@var{value}, @var{c}, @var{str})
+Like @code{CONST_DOUBLE_OK_FOR_LETTER_P}, but you also get the constraint
+string passed in @var{str}, so that you can use suffixes to distinguish
+between different variants.
+
 @findex EXTRA_CONSTRAINT
 @item EXTRA_CONSTRAINT (@var{value}, @var{c})
 A C expression that defines the optional machine-dependent constraint
 letters that can be used to segregate specific types of operands, usually
 memory references, for the target machine.  Any letter that is not
-elsewhere defined and not matched by @code{REG_CLASS_FROM_LETTER}
+elsewhere defined and not matched by @code{REG_CLASS_FROM_LETTER} /
+@code{REG_CLASS_FROM_CONSTRAINT}
 may be used.  Normally this macro will not be defined.
 
 If it is required for a particular target machine, it should return 1
@@ -2643,14 +2678,21 @@ a @samp{Q} constraint on the input and @
 alternative specifies @samp{m} on the input and a register class that
 does not include r0 on the output.
 
+@findex EXTRA_CONSTRAINT_STR
+@item EXTRA_CONSTRAINT_STR (@var{value}, @var{c}, @var{str})
+Like @code{EXTRA_CONSTRAINT}, but you also get the constraint string passed
+in @var{str}, so that you can use suffixes to distinguish between different
+variants.
+
 @findex EXTRA_MEMORY_CONSTRAINT
-@item EXTRA_MEMORY_CONSTRAINT (@var{c})
+@item EXTRA_MEMORY_CONSTRAINT (@var{c}, @var{str})
 A C expression that defines the optional machine-dependent constraint
 letters, amongst those accepted by @code{EXTRA_CONSTRAINT}, that should
 be treated like memory constraints by the reload pass.
 
 It should return 1 if the operand type represented by the constraint 
-letter @var{c} comprises a subset of all memory references including
+at the start of @var{str}, the first letter of which is the letter @var{c},
+ comprises a subset of all memory references including
 all those whose address is simply a base register.  This allows the reload 
 pass to reload an operand, if it does not directly correspond to the operand 
 type of @var{c}, by copying its address into a base register.
@@ -2666,16 +2708,18 @@ into a base register if required.  This 
 a @samp{o} constraint can handle any memory operand.
 
 @findex EXTRA_ADDRESS_CONSTRAINT
-@item EXTRA_ADDRESS_CONSTRAINT (@var{c})
+@item EXTRA_ADDRESS_CONSTRAINT (@var{c}, @var{str})
 A C expression that defines the optional machine-dependent constraint
-letters, amongst those accepted by @code{EXTRA_CONSTRAINT}, that should
+letters, amongst those accepted by @code{EXTRA_CONSTRAINT} /
+@code{EXTRA_CONSTRAINT_STR}, that should
 be treated like address constraints by the reload pass.
 
 It should return 1 if the operand type represented by the constraint 
-letter @var{c} comprises a subset of all memory addresses including
+at the startr of @{str}, which starts with the letter @var{c}, comprises
+a subset of all memory addresses including
 all those that consist of just a base register.  This allows the reload 
 pass to reload an operand, if it does not directly correspond to the operand 
-type of @var{c}, by copying it into a base register.
+type of @var{str}, by copying it into a base register.
 
 Any constraint marked as @code{EXTRA_ADDRESS_CONSTRAINT} can only
 be used with the @code{address_operand} predicate.  It is treated 
Index: config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.55
diff -p -u -r1.55 s390.h
--- config/s390/s390.h	20 Dec 2002 13:02:42 -0000	1.55
+++ config/s390/s390.h	7 Jan 2003 20:10:05 -0000
@@ -473,7 +473,7 @@ extern const enum reg_class regclass_map
      ((C) == 'Q' ?  q_constraint (OP) : 			\
       (C) == 'S' ?  larl_operand (OP, GET_MODE (OP)) : 0)
 
-#define EXTRA_MEMORY_CONSTRAINT(C) ((C) == 'Q')
+#define EXTRA_MEMORY_CONSTRAINT(C,STR) ((C) == 'Q')
 
 
 /* Stack layout and calling conventions.  */

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