c-parse.in (asm_operand): Allow named operands.
authorRichard Henderson <rth@redhat.com>
Thu, 11 Oct 2001 07:07:30 +0000 (00:07 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 11 Oct 2001 07:07:30 +0000 (00:07 -0700)
        * c-parse.in (asm_operand): Allow named operands.
        * genconfig.c (max_recog_operands): Set to 29.
        * local-alloc.c (requires_inout): Skip multiple digits.
        * recog.c (asm_operand_ok): Likewise.
        (preprocess_constraints): Use strtoul for matching constraints.
        (constrain_operands): Likewise.
        * regmove.c (find_matches): Likewise.
        * reload.c (find_reloads): Likewise.
        * stmt.c (parse_output_constraint): Don't reject in-out
        constraint on operands > 9.  Reject '[' in constraint.
        (expand_asm_operands): Handle named operands.  Use strtoul
        for matching constraints.
        (check_operand_nalternatives): Split out from expand_asm_operands.
        (check_unique_operand_names): New.
        (resolve_operand_names, resolve_operand_name_1): New.

        * doc/extend.texi (Extended Asm): Document named operands.
        * doc/md.texi (Simple Constraints): Document matching constraints
        on operands > 9.

        * parse.y (asm_operand): Allow named operands.
        * semantics.c (finish_asm_stmt): Tweek for changed location
        of the operand constrant.

From-SVN: r46179

13 files changed:
gcc/ChangeLog
gcc/c-parse.in
gcc/cp/ChangeLog
gcc/cp/parse.y
gcc/cp/semantics.c
gcc/doc/extend.texi
gcc/doc/md.texi
gcc/genconfig.c
gcc/local-alloc.c
gcc/recog.c
gcc/regmove.c
gcc/reload.c
gcc/stmt.c

index 5e491e9..b322551 100644 (file)
@@ -1,5 +1,27 @@
 2001-10-10  Richard Henderson  <rth@redhat.com>
 
+       * c-parse.in (asm_operand): Allow named operands.
+       * genconfig.c (max_recog_operands): Set to 29.
+       * local-alloc.c (requires_inout): Skip multiple digits.
+       * recog.c (asm_operand_ok): Likewise.
+       (preprocess_constraints): Use strtoul for matching constraints.
+       (constrain_operands): Likewise.
+       * regmove.c (find_matches): Likewise.
+       * reload.c (find_reloads): Likewise.
+       * stmt.c (parse_output_constraint): Don't reject in-out
+       constraint on operands > 9.  Reject '[' in constraint.
+       (expand_asm_operands): Handle named operands.  Use strtoul
+       for matching constraints.
+       (check_operand_nalternatives): Split out from expand_asm_operands.
+       (check_unique_operand_names): New.
+       (resolve_operand_names, resolve_operand_name_1): New.
+
+       * doc/extend.texi (Extended Asm): Document named operands.
+       * doc/md.texi (Simple Constraints): Document matching constraints
+       on operands > 9.
+
+2001-10-10  Richard Henderson  <rth@redhat.com>
+
        * combine.c (try_combine): Handle a SEQUENCE of one insn.
 
        * i386.c (test splitter): Narrow tests vs paradoxical subregs.
index 28ac2b5..8096d1c 100644 (file)
@@ -2454,7 +2454,9 @@ nonnull_asm_operands:
 
 asm_operand:
          STRING '(' expr ')'
-               { $$ = build_tree_list ($1, $3); }
+               { $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
+       | '[' identifier ']' STRING '(' expr ')'
+               { $$ = build_tree_list (build_tree_list ($2, $4), $6); }
        ;
 
 asm_clobbers:
index 49fdb78..8d867bb 100644 (file)
@@ -1,3 +1,9 @@
+2001-10-10  Richard Henderson  <rth@redhat.com>
+
+        * parse.y (asm_operand): Allow named operands.
+       * semantics.c (finish_asm_stmt): Tweek for changed location
+       of the operand constrant.
+
 2001-10-09  Jason Merrill  <jason_merrill@redhat.com>
 
        * call.c (standard_conversion): Add bad conversion between
index a7651b5..f3e85ff 100644 (file)
@@ -3607,7 +3607,9 @@ nonnull_asm_operands:
 
 asm_operand:
          STRING '(' expr ')'
-               { $$ = build_tree_list ($$, $3); }
+               { $$ = build_tree_list (build_tree_list (NULL_TREE, $1), $3); }
+       | '[' identifier ']' STRING '(' expr ')'
+               { $$ = build_tree_list (build_tree_list ($2, $4), $6); }
        ;
 
 asm_clobbers:
index ec7b968..41e3bcf 100644 (file)
@@ -929,7 +929,7 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
          const char *constraint;
          tree operand;
 
-         constraint = TREE_STRING_POINTER (TREE_PURPOSE (t));
+         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
          operand = TREE_VALUE (output_operands);
 
          if (!parse_output_constraint (&constraint,
index 027647d..132ccba 100644 (file)
@@ -3382,14 +3382,34 @@ Each operand is described by an operand-constraint string followed by
 the C expression in parentheses.  A colon separates the assembler
 template from the first output operand and another separates the last
 output operand from the first input, if any.  Commas separate the
-operands within each group.  The total number of operands is limited to
-ten or to the maximum number of operands in any instruction pattern in
-the machine description, whichever is greater.
+operands within each group.  The total number of operands is currently
+limited to 30; this limitation may be lifted in some future version of
+GCC.
 
 If there are no output operands but there are input operands, you must
 place two consecutive colons surrounding the place where the output
 operands would go.
 
+As of GCC version 3.1, it is also possible to specify input and output
+operands using symbolic names which can be referenced within the
+assembler code.  These names are specified inside square brackets
+preceding the constraint string, and can be referenced inside the
+assembler code using @code{%[@var{name}]} instead of a percentage sign
+followed by the operand number.  Using named operands the above example
+could look like:
+
+@example
+asm ("fsinx %[angle],%[output]"
+     : [output] "=f" (result)
+     : [angle] "f" (angle));
+@end example
+
+@noindent
+Note that the symbolic operand names have no relation whatsoever to
+other C identifiers.  You may use any name you like, even those of
+existing C symbols, but must ensure that no two operands within the same
+assembler construct use the same symbolic name.
+
 Output operand expressions must be lvalues; the compiler can check this.
 The input operands need not be lvalues.  The compiler cannot check
 whether the operands have data types that are reasonable for the
@@ -3425,10 +3445,10 @@ asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar));
 
 @noindent
 The constraint @samp{"0"} for operand 1 says that it must occupy the
-same location as operand 0.  A digit in constraint is allowed only in an
-input operand and it must refer to an output operand.
+same location as operand 0.  A number in constraint is allowed only in
+an input operand and it must refer to an output operand.
 
-Only a digit in the constraint can guarantee that one operand will be in
+Only a number in the constraint can guarantee that one operand will be in
 the same place as another.  The mere fact that @code{foo} is the value
 of both operands is not enough to guarantee that they will be in the
 same place in the generated assembler code.  The following would not
@@ -3446,6 +3466,15 @@ register (copying it afterward to @code{foo}'s own address).  Of course,
 since the register for operand 1 is not even mentioned in the assembler
 code, the result will not work, but GCC can't tell that.
 
+As of GCC version 3.1, one may write @code{[@var{name}]} instead of
+the operand number for a matching constraint.  For example:
+
+@example
+asm ("cmoveq %1,%2,%[result]"
+     : [result] "=r"(result)
+     : "r" (test), "r"(new), "[result]"(old));
+@end example
+
 Some instructions clobber specific hard registers.  To describe this,
 write a third colon after the input operands, followed by the names of
 the clobbered hard registers (given as strings).  Here is a realistic
index 685f515..7a62eaf 100644 (file)
@@ -894,6 +894,13 @@ An operand that matches the specified operand number is allowed.  If a
 digit is used together with letters within the same alternative, the
 digit should come last.
 
+This number is allowed to be more than a single digit.  If multiple
+digits are encountered consecutavely, they are interpreted as a single
+decimal integer.  There is scant chance for ambiguity, since to-date
+it has never been desirable that @samp{10} be interpreted as matching
+either operand 1 @emph{or} operand 0.  Should this be desired, one
+can use multiple alternatives instead.
+
 @cindex matching constraint
 @cindex constraint, matching
 This is called a @dfn{matching constraint} and what it really means is
index f9ae6d5..27000be 100644 (file)
@@ -285,8 +285,10 @@ main (argc, argv)
   puts ("#ifndef GCC_INSN_CONFIG_H");
   puts ("#define GCC_INSN_CONFIG_H\n");
 
-  /* Allow at least 10 operands for the sake of asm constructs.  */
-  max_recog_operands = 9;  /* We will add 1 later.  */
+  /* Allow at least 30 operands for the sake of asm constructs.  */
+  /* ??? We *really* ought to reorganize things such that there
+     is no fixed upper bound.  */
+  max_recog_operands = 29;  /* We will add 1 later.  */
   max_dup_operands = 1;
 
   /* Read the machine description.  */
index 2637b7e..22d7d48 100644 (file)
@@ -1302,7 +1302,7 @@ block_alloc (b)
              for (i = 1; i < recog_data.n_operands; i++)
                {
                  const char *p = recog_data.constraints[i];
-                 int this_match = (requires_inout (p));
+                 int this_match = requires_inout (p);
 
                  n_matching_alts += this_match;
                  if (this_match == recog_data.n_alternatives)
@@ -2409,8 +2409,6 @@ requires_inout (p)
       case '=':  case '+':  case '?':
       case '#':  case '&':  case '!':
       case '*':  case '%':
-      case '1':  case '2':  case '3':  case '4': case '5':
-      case '6':  case '7':  case '8':  case '9':
       case 'm':  case '<':  case '>':  case 'V':  case 'o':
       case 'E':  case 'F':  case 'G':  case 'H':
       case 's':  case 'i':  case 'n':
@@ -2431,6 +2429,13 @@ requires_inout (p)
        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 (*p >= '0' && *p <= '9')
+         p++;
+       break;
+
       default:
        if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
          break;
index e240ebb..1504870 100644 (file)
@@ -1657,6 +1657,8 @@ 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 (*constraint >= '0' && *constraint <= '9')
+           constraint++;
          result = -1;
          break;
 
@@ -2211,8 +2213,12 @@ preprocess_constraints ()
 
                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';
-                 recog_op_alt[op_alt[j].matches][j].matched = i;
+                 {
+                   char *end;
+                   op_alt[j].matches = strtoul (p - 1, &end, 10);
+                   recog_op_alt[op_alt[j].matches][j].matched = i;
+                   p = end;
+                 }
                  break;
 
                case 'm':
@@ -2364,45 +2370,54 @@ constrain_operands (strict)
 
              case '0':  case '1':  case '2':  case '3':  case '4':
              case '5':  case '6':  case '7':  case '8':  case '9':
+               {
+                 /* 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.
 
-               /* 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.
 
-                  Note that the lower-numbered operand is passed first.
+                    If we are not testing strictly, assume that this
+                    constraint will be satisfied.  */
 
-                  If we are not testing strictly, assume that this constraint
-                  will be satisfied.  */
-               if (strict < 0)
-                 val = 1;
-               else
-                 {
-                   rtx op1 = recog_data.operand[c - '0'];
-                   rtx op2 = recog_data.operand[opno];
+                 char *end;
+                 int match;
 
-                   /* A unary operator may be accepted by the predicate,
-                      but it is irrelevant for matching constraints.  */
-                   if (GET_RTX_CLASS (GET_CODE (op1)) == '1')
-                     op1 = XEXP (op1, 0);
-                   if (GET_RTX_CLASS (GET_CODE (op2)) == '1')
-                     op2 = XEXP (op2, 0);
+                 match = strtoul (p - 1, &end, 10);
+                 p = end;
 
-                   val = operands_match_p (op1, op2);
-                 }
+                 if (strict < 0)
+                   val = 1;
+                 else
+                   {
+                     rtx op1 = recog_data.operand[match];
+                     rtx op2 = recog_data.operand[opno];
 
-               matching_operands[opno] = c - '0';
-               matching_operands[c - '0'] = opno;
+                     /* A unary operator may be accepted by the predicate,
+                        but it is irrelevant for matching constraints.  */
+                     if (GET_RTX_CLASS (GET_CODE (op1)) == '1')
+                       op1 = XEXP (op1, 0);
+                     if (GET_RTX_CLASS (GET_CODE (op2)) == '1')
+                       op2 = XEXP (op2, 0);
 
-               if (val != 0)
-                 win = 1;
-               /* If output is *x and input is *--x,
-                  arrange later to change the output to *--x as well,
-                  since the output op is the one that will be printed.  */
-               if (val == 2 && strict > 0)
-                 {
-                   funny_match[funny_match_index].this = opno;
-                   funny_match[funny_match_index++].other = c - '0';
-                 }
+                     val = operands_match_p (op1, op2);
+                   }
+
+                 matching_operands[opno] = match;
+                 matching_operands[match] = opno;
+
+                 if (val != 0)
+                   win = 1;
+
+                 /* If output is *x and input is *--x, arrange later
+                    to change the output to *--x as well, since the
+                    output op is the one that will be printed.  */
+                 if (val == 2 && strict > 0)
+                   {
+                     funny_match[funny_match_index].this = opno;
+                     funny_match[funny_match_index++].other = match;
+                   }
+               }
                break;
 
              case 'p':
index ce62cce..89a55ca 100644 (file)
@@ -1576,16 +1576,23 @@ find_matches (insn, matchp)
            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':
-           c -= '0';
-           if (c < op_no && likely_spilled[(unsigned char) c])
-             break;
-           matchp->with[op_no] = c;
-           any_matches = 1;
-           if (matchp->commutative[op_no] >= 0)
-             matchp->with[matchp->commutative[op_no]] = c;
+           {
+             char *end;
+             unsigned long match = strtoul (p - 1, &end, 10);
+             p = end;
+
+             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;
+
          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':
index 613d6c7..8b01ce2 100644 (file)
@@ -2551,7 +2551,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            }
          else if (c >= '0' && c <= '9')
            {
-             c -= '0';
+             c = strtoul (p - 1, &p, 10);
+
              operands_match[c][i]
                = operands_match_p (recog_data.operand[c],
                                    recog_data.operand[i]);
@@ -2939,8 +2940,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
              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);
 
-               c -= '0';
                this_alternative_matches[i] = c;
                /* We are supposed to match a previous operand.
                   If we do, we win if that one did.
index b7ced6a..1f91823 100644 (file)
@@ -404,6 +404,11 @@ static void expand_nl_goto_receiver        PARAMS ((void));
 static void expand_nl_goto_receivers   PARAMS ((struct nesting *));
 static void fixup_gotos                        PARAMS ((struct nesting *, rtx, tree,
                                               rtx, int));
+static bool check_operand_nalternatives        PARAMS ((tree, tree));
+static bool check_unique_operand_names PARAMS ((tree, tree));
+static tree resolve_operand_names      PARAMS ((tree, tree, tree,
+                                                const char **));
+static char *resolve_operand_name_1    PARAMS ((char *, tree, tree));
 static void expand_null_return_1       PARAMS ((rtx));
 static void expand_value_return                PARAMS ((rtx));
 static int tail_recursion_args         PARAMS ((tree, tree));
@@ -1355,14 +1360,6 @@ parse_output_constraint (constraint_p,
      from and written to.  */
   *is_inout = (*p == '+');
 
-  /* Make sure we can specify the matching operand.  */
-  if (*is_inout && operand_num > 9)
-    {
-      error ("output operand constraint %d contains `+'", 
-            operand_num);
-      return false;
-    }
-
   /* Canonicalize the output constraint so that it begins with `='.  */
   if (p != constraint || is_inout)
     {
@@ -1416,6 +1413,7 @@ parse_output_constraint (constraint_p,
 
       case '0':  case '1':  case '2':  case '3':  case '4':
       case '5':  case '6':  case '7':  case '8':  case '9':
+      case '[':
        error ("matching constraint not valid in output operand");
        return false;
 
@@ -1478,7 +1476,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
      const char *filename;
      int line;
 {
-  rtvec argvec, constraints;
+  rtvec argvec, constraintvec;
   rtx body;
   int ninputs = list_length (inputs);
   int noutputs = list_length (outputs);
@@ -1492,8 +1490,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   rtx *real_output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
   enum machine_mode *inout_mode
     = (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
-  const char **output_constraints
-    = alloca (noutputs * sizeof (const char *));
+  const char **constraints
+    = (const char **) alloca ((noutputs + ninputs) * sizeof (const char *));
   /* The insn we have emitted.  */
   rtx insn;
   int old_generating_concat_p = generating_concat_p;
@@ -1504,10 +1502,18 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   if (current_function_check_memory_usage)
     {
-      error ("`asm' cannot be used with `-fcheck-memory-usage'");
+      error ("`asm' cannot be used in function where memory usage is checked");
       return;
     }
 
+  if (! check_operand_nalternatives (outputs, inputs))
+    return;
+
+  if (! check_unique_operand_names (outputs, inputs))
+    return;
+
+  string = resolve_operand_names (string, outputs, inputs, constraints);
+
 #ifdef MD_ASM_CLOBBERS
   /* Sometimes we wish to automatically clobber registers across an asm.
      Case in point is when the i386 backend moved from cc0 to a hard reg --
@@ -1516,12 +1522,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   MD_ASM_CLOBBERS (clobbers);
 #endif
 
-  if (current_function_check_memory_usage)
-    {
-      error ("`asm' cannot be used in function where memory usage is checked");
-      return;
-    }
-
   /* Count the number of meaningful clobbered registers, ignoring what
      we would ignore later.  */
   nclobbers = 0;
@@ -1538,43 +1538,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   last_expr_type = 0;
 
-  /* Check that the number of alternatives is constant across all
-     operands.  */
-  if (outputs || inputs)
-    {
-      tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
-      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)
-       {
-         const char *constraint = TREE_STRING_POINTER (TREE_PURPOSE (tmp));
-
-         if (n_occurrences (',', constraint) != nalternatives)
-           {
-             error ("operand constraints for `asm' differ in number of alternatives");
-             return;
-           }
-
-         if (TREE_CHAIN (tmp))
-           tmp = TREE_CHAIN (tmp);
-         else
-           tmp = next, next = 0;
-       }
-    }
-
   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
     {
       tree val = TREE_VALUE (tail);
       tree type = TREE_TYPE (val);
-      const char *constraint;
       bool is_inout;
       bool allows_reg;
       bool allows_mem;
@@ -1588,12 +1555,9 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
         the worst that happens if we get it wrong is we issue an error
         message.  */
 
-      constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
-      output_constraints[i] = constraint;
-
       /* Try to parse the output constraint.  If that fails, there's
         no point in going further.  */
-      if (!parse_output_constraint (&output_constraints[i],
+      if (!parse_output_constraint (&constraints[i],
                                    i,
                                    ninputs,
                                    noutputs,
@@ -1659,15 +1623,16 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       return;
     }
 
-  /* Make vectors for the expression-rtx and constraint strings.  */
+  /* Make vectors for the expression-rtx, constraint strings,
+     and named operands.  */
 
   argvec = rtvec_alloc (ninputs);
-  constraints = rtvec_alloc (ninputs);
+  constraintvec = rtvec_alloc (ninputs);
 
   body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
                                : GET_MODE (output_rtx[0])),
                               TREE_STRING_POINTER (string), 
-                              empty_string, 0, argvec, constraints,
+                              empty_string, 0, argvec, constraintvec,
                               filename, line);
 
   MEM_VOLATILE_P (body) = vol;
@@ -1675,8 +1640,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   /* Eval the inputs and put them into ARGVEC.
      Put their constraints into ASM_INPUTs and store in CONSTRAINTS.  */
 
-  i = 0;
-  for (tail = inputs; tail; tail = TREE_CHAIN (tail))
+  for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
     {
       int j;
       int allows_reg = 0, allows_mem = 0;
@@ -1698,9 +1662,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          return;
        }
 
-      constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+      orig_constraint = constraint = constraints[i + noutputs];
       c_len = strlen (constraint);
-      orig_constraint = constraint;
 
       /* Make sure constraint has neither `=', `+', nor '&'.  */
 
@@ -1744,28 +1707,30 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
               operands to memory.  */
          case '0':  case '1':  case '2':  case '3':  case '4':
          case '5':  case '6':  case '7':  case '8':  case '9':
-           if (constraint[j] >= '0' + noutputs)
-             {
-               error
-                 ("matching constraint references invalid operand number");
-               return;
-             }
-
-           /* Try and find the real constraint for this dup.  */
-           if ((j == 0 && c_len == 1)
-               || (j == 1 && c_len == 2 && constraint[0] == '%'))
-             {
-               tree o = outputs;
-
-               for (j = constraint[j] - '0'; j > 0; --j)
-                 o = TREE_CHAIN (o);
+           {
+             char *end;
+             unsigned long match;
 
-               constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
-               c_len = strlen (constraint);
-               j = 0;
-               break;
-             }
+             match = strtoul (constraint + j, &end, 10);
+             if (match >= (unsigned long) noutputs)
+               {
+                 error ("matching constraint references invalid operand number");
+                 return;
+               }
 
+             /* Try and find the real constraint for this dup.  Only do
+                this if the matching constraint is the only alternative.  */
+             if (*end == '\0'
+                 && (j == 0 || (j == 1 && constraint[0] == '%')))
+               {
+                 constraint = constraints[match];
+                 c_len = strlen (constraint);
+                 j = 0;
+                 break;
+               }
+             else
+               j = end - constraint;
+           }
            /* Fall through.  */
 
          case 'p':  case 'r':
@@ -1814,7 +1779,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          if (allows_reg)
            op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
          else if (!allows_mem)
-           warning ("asm operand %d probably doesn't match constraints", i);
+           warning ("asm operand %d probably doesn't match constraints",
+                    i + noutputs);
          else if (CONSTANT_P (op))
            op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
                                  op);
@@ -1843,7 +1809,8 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            /* ??? Leave this only until we have experience with what
               happens in combine and elsewhere when constraints are
               not satisfied.  */
-           warning ("asm operand %d probably doesn't match constraints", i);
+           warning ("asm operand %d probably doesn't match constraints",
+                    i + noutputs);
        }
       generating_concat_p = old_generating_concat_p;
       ASM_OPERANDS_INPUT (body, i) = op;
@@ -1851,7 +1818,6 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
        = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
                             orig_constraint);
-      i++;
     }
 
   /* Protect all the operands from the queue now that they have all been
@@ -1870,24 +1836,26 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   for (i = 0; i < ninout; i++)
     {
       int j = inout_opnum[i];
+      char buffer[16];
 
       ASM_OPERANDS_INPUT (body, ninputs - ninout + i)
        = output_rtx[j];
+
+      sprintf (buffer, "%d", j);
       ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, ninputs - ninout + i)
-       = gen_rtx_ASM_INPUT (inout_mode[i], digit_string (j));
+       = gen_rtx_ASM_INPUT (inout_mode[i], ggc_alloc_string (buffer, -1));
     }
 
   generating_concat_p = old_generating_concat_p;
 
   /* Now, for each output, construct an rtx
-     (set OUTPUT (asm_operands INSN OUTPUTNUMBER OUTPUTCONSTRAINT
-                              ARGVEC CONSTRAINTS))
+     (set OUTPUT (asm_operands INSN OUTPUTCONSTRAINT OUTPUTNUMBER
+                              ARGVEC CONSTRAINTS OPNAMES))
      If there is more than one, put them inside a PARALLEL.  */
 
   if (noutputs == 1 && nclobbers == 0)
     {
-      ASM_OPERANDS_OUTPUT_CONSTRAINT (body)
-       = output_constraints[0];
+      ASM_OPERANDS_OUTPUT_CONSTRAINT (body) = constraints[0];
       insn = emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
     }
 
@@ -1916,8 +1884,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
                           gen_rtx_ASM_OPERANDS
                           (GET_MODE (output_rtx[i]),
                            TREE_STRING_POINTER (string),
-                           output_constraints[i],
-                           i, argvec, constraints,
+                           constraints[i], i, argvec, constraintvec,
                            filename, line));
 
          MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
@@ -1971,6 +1938,206 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   free_temp_slots ();
 }
+
+/* A subroutine of expand_asm_operands.  Check that all operands have
+   the same number of alternatives.  Return true if so.  */
+
+static bool
+check_operand_nalternatives (outputs, inputs)
+     tree outputs, inputs;
+{
+  if (outputs || inputs)
+    {
+      tree tmp = TREE_PURPOSE (outputs ? outputs : inputs);
+      int nalternatives
+       = n_occurrences (',', TREE_STRING_POINTER (TREE_VALUE (tmp)));
+      tree next = inputs;
+
+      if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
+       {
+         error ("too many alternatives in `asm'");
+         return false;
+       }
+
+      tmp = outputs;
+      while (tmp)
+       {
+         const char *constraint
+           = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tmp)));
+
+         if (n_occurrences (',', constraint) != nalternatives)
+           {
+             error ("operand constraints for `asm' differ in number of alternatives");
+             return false;
+           }
+
+         if (TREE_CHAIN (tmp))
+           tmp = TREE_CHAIN (tmp);
+         else
+           tmp = next, next = 0;
+       }
+    }
+
+  return true;
+}
+
+/* A subroutine of expand_asm_operands.  Check that all operand names
+   are unique.  Return true if so.  We rely on the fact that these names
+   are identifiers, and so have been canonicalized by get_identifier,
+   so all we need are pointer comparisons.  */
+
+static bool
+check_unique_operand_names (outputs, inputs)
+     tree outputs, inputs;
+{
+  tree i, j;
+
+  for (i = outputs; i ; i = TREE_CHAIN (i))
+    {
+      tree i_name = TREE_PURPOSE (TREE_PURPOSE (i));
+      if (! i_name)
+       continue;
+
+      for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
+       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+         goto failure;
+    }
+
+  for (i = inputs; i ; i = TREE_CHAIN (i))
+    {
+      tree i_name = TREE_PURPOSE (TREE_PURPOSE (i));
+      if (! i_name)
+       continue;
+
+      for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
+       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+         goto failure;
+      for (j = outputs; j ; j = TREE_CHAIN (j))
+       if (i_name == TREE_PURPOSE (TREE_PURPOSE (j)))
+         goto failure;
+    }
+
+  return true;
+
+ failure:
+  error ("duplicate asm operand name '%s'",
+        IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (i))));
+  return false;
+}
+
+/* A subroutine of expand_asm_operands.  Resolve the names of the operands
+   in *POUTPUTS and *PINPUTS to numbers, and replace the name expansions in
+   STRING and in the constraints to those numbers.  */
+
+static tree
+resolve_operand_names (string, outputs, inputs, pconstraints)
+     tree string;
+     tree outputs, inputs;
+     const char **pconstraints;
+{
+  char *buffer = xstrdup (TREE_STRING_POINTER (string));
+  char *p;
+  tree t;
+
+  /* Assume that we will not need extra space to perform the substitution.
+     This because we get to remove '[' and ']', which means we cannot have
+     a problem until we have more than 999 operands.  */
+
+  p = buffer;
+  while ((p = strchr (p, '%')) != NULL)
+    {
+      if (*++p != '[')
+       continue;
+      p = resolve_operand_name_1 (p, outputs, inputs);
+    }
+
+  string = build_string (strlen (buffer), buffer);
+  free (buffer);
+
+  /* Collect output constraints here because it's convenient.
+     There should be no named operands here; this is verified
+     in expand_asm_operand.  */
+  for (t = outputs; t ; t = TREE_CHAIN (t), pconstraints++)
+    *pconstraints = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+  /* Substitute [<name>] in input constraint strings.  */
+  for (t = inputs; t ; t = TREE_CHAIN (t), pconstraints++)
+    {
+      const char *c = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+      if (strchr (c, '[') == NULL)
+       *pconstraints = c;
+      else
+       {
+         p = buffer = xstrdup (c);
+         while ((p = strchr (p, '[')) != NULL)
+           p = resolve_operand_name_1 (p, outputs, inputs);
+
+         *pconstraints = ggc_alloc_string (buffer, -1);
+         free (buffer);
+       }
+    }
+
+  return string;
+}
+
+/* A subroutine of resolve_operand_names.  P points to the '[' for a
+   potential named operand of the form [<name>].  In place, replace
+   the name and brackets with a number.  Return a pointer to the 
+   balance of the string after substitution.  */
+
+static char *
+resolve_operand_name_1 (p, outputs, inputs)
+     char *p;
+     tree outputs, inputs;
+{
+  char *q;
+  int op;
+  tree t;
+  size_t len;
+
+  /* Collect the operand name.  */
+  q = strchr (p, ']');
+  if (!q)
+    {
+      error ("missing close brace for named operand");
+      return strchr (p, '\0');
+    }
+  len = q - p - 1;
+
+  /* Resolve the name to a number.  */
+  for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
+    {
+      const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
+      if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+       goto found;
+    }
+  for (t = inputs; t ; t = TREE_CHAIN (t), op++)
+    {
+      const char *c = IDENTIFIER_POINTER (TREE_PURPOSE (TREE_PURPOSE (t)));
+      if (strncmp (c, p + 1, len) == 0 && c[len] == '\0')
+       goto found;
+    }
+
+  *q = '\0';
+  error ("undefined named operand '%s'", p + 1);
+  op = 0;
+ found:
+
+  /* Replace the name with the number.  Unfortunately, not all libraries
+     get the return value of sprintf correct, so search for the end of the
+     generated string by hand.  */
+  sprintf (p, "%d", op);
+  p = strchr (p, '\0');
+
+  /* Verify the no extra buffer space assumption.  */
+  if (p > q)
+    abort ();
+
+  /* Shift the rest of the buffer down to fill the gap.  */
+  memmove (p, q + 1, strlen (q + 1) + 1);
+
+  return p;
+}
 \f
 /* Generate RTL to evaluate the expression EXP
    and remember it in case this is the VALUE in a ({... VALUE; }) constr.  */