OSDN Git Service

* stmt.c (parse_input_constraint): Break out from ...
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 24 Dec 2001 05:57:02 +0000 (05:57 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 24 Dec 2001 05:57:02 +0000 (05:57 +0000)
        (expand_asm_operands): ... here.  Loop over the operands twice,
        the first time only calling mark_addressable.  Correct and simplify
        the conditions for spilling an output operand to memory.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@48298 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/stmt.c
gcc/testsuite/gcc.c-torture/compile/20011205-1.c [new file with mode: 0644]

index 9082c2b..4996eb1 100644 (file)
@@ -1,5 +1,12 @@
 2001-12-23  Richard Henderson  <rth@redhat.com>
 
+       * stmt.c (parse_input_constraint): Break out from ...
+       (expand_asm_operands): ... here.  Loop over the operands twice,
+       the first time only calling mark_addressable.  Correct and simplify
+       the conditions for spilling an output operand to memory.
+
+2001-12-23  Richard Henderson  <rth@redhat.com>
+
        * config/alpha/alpha.c (call_operand) [OSF]: Disallow virtual regs.
 
        * config/alpha/alpha.md (UNSPEC_SIBCALL): New.
 
 2001-12-22  Aldy Hernandez  <aldyh@redhat.com>
 
-        * config/rs6000/rs6000.h (rs6000_builtins): Add vsldoi variants.
+       * config/rs6000/rs6000.h (rs6000_builtins): Add vsldoi variants.
 
-        * config/rs6000/rs6000.md ("altivec_vsldoi_*"): Same.
+       * config/rs6000/rs6000.md ("altivec_vsldoi_*"): Same.
 
-        * config/rs6000/rs6000.c: Clean up some spacing and indentation.
-        (altivec_init_builtins): Add tree types for builtins with 4 bit
-        literals.
+       * config/rs6000/rs6000.c: Clean up some spacing and indentation.
+       (altivec_init_builtins): Add tree types for builtins with 4 bit
+       literals.
        (bdesc_3arg): Add vsldoi variants.
 
 2001-12-22  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
@@ -248,16 +255,16 @@ Fri Dec 21 17:30:15 2001  Jeffrey A Law  (law@redhat.com)
 2001-12-20  Nick Clifton  <nickc@cambridge.redhat.com>
 
        * config/arm/arm.c (arm_compute_save_reg0_reg12_mask):  New
-        function. Compute which of registers r0 through r12 should be
+       function. Compute which of registers r0 through r12 should be
        saved onto the stack during a function's prologue.
-        (arm_compute_save_reg_mask): Use
-        arm_compute_save_reg0_reg12_mask.
-        (arm_compute_initial_elimination_offset): Use
-        arm_compute_save_reg0_reg12_mask.
+       (arm_compute_save_reg_mask): Use
+       arm_compute_save_reg0_reg12_mask.
+       (arm_compute_initial_elimination_offset): Use
+       arm_compute_save_reg0_reg12_mask.
 
-        (arm_expand_prologue): Do not mark as save of the IP register
-        for an interrupt handler as being part of the frame creation
-        code.
+       (arm_expand_prologue): Do not mark as save of the IP register
+       for an interrupt handler as being part of the frame creation
+       code.
 
 2001-12-20  Richard Henderson  <rth@redhat.com>
 
@@ -320,30 +327,30 @@ Thu Dec 20 16:58:46 CET 2001  Jan Hubicka  <jh@suse.cz>
 
 2001-12-19  Aldy Hernandez  <aldyh@redhat.com>
 
-        * doc/install.texi: Add documentation for --enable-altivec.
+       * doc/install.texi: Add documentation for --enable-altivec.
 
-        * config.gcc: Add support for --enable-altivec.
+       * config.gcc: Add support for --enable-altivec.
 
-        * config/rs6000/altivec.h: New.
+       * config/rs6000/altivec.h: New.
 
-        * config/rs6000/linuxaltivec.h (SUBSUBTARGET_OVERRIDE_OPTIONS):
-        Define.  Fix typo.
+       * config/rs6000/linuxaltivec.h (SUBSUBTARGET_OVERRIDE_OPTIONS):
+       Define.  Fix typo.
 
-        * config/rs6000/rs6000.c (vrsave_operation): Change unspec to
+       * config/rs6000/rs6000.c (vrsave_operation): Change unspec to
        unspec_volatile.
-        (generate_set_vrsave): Generate the unspec here instead of calling
-        an .md pattern.
-        (generate_set_vrsave): Use gen_rtvec.
-        (rs6000_emit_prologue): Replace call to gen_get_vrsave with
-        gen_rtx_SET.
+       (generate_set_vrsave): Generate the unspec here instead of calling
+       an .md pattern.
+       (generate_set_vrsave): Use gen_rtvec.
+       (rs6000_emit_prologue): Replace call to gen_get_vrsave with
+       gen_rtx_SET.
 
-        * config/rs6000/rs6000.md ("*movsi_internal1"): Add constraints
+       * config/rs6000/rs6000.md ("*movsi_internal1"): Add constraints
        for setting special registers.
-        ("*set_vrsave_internal"): Use unspec_volatile.
-        ("set_vrsave"): Remove.
-        ("get_vrsave"): Remove.
+       ("*set_vrsave_internal"): Use unspec_volatile.
+       ("set_vrsave"): Remove.
+       ("get_vrsave"): Remove.
 
-        * config/rs6000/rs6000.h (REG_CLASS_CONTENTS): Add vrsave to
+       * config/rs6000/rs6000.h (REG_CLASS_CONTENTS): Add vrsave to
        SPECIAL_REGS.
 
 2001-12-19  Bruce Korb  <bkorb@gnu.org>
index 7978554..5682a26 100644 (file)
@@ -397,6 +397,9 @@ struct stmt_status
 static int using_eh_for_cleanups_p = 0;
 
 static int n_occurrences               PARAMS ((int, const char *));
+static bool parse_input_constraint     PARAMS ((const char **, int, int, int,
+                                                int, const char * const *,
+                                                bool *, bool *));
 static void expand_goto_internal       PARAMS ((tree, rtx, rtx));
 static int expand_fixup                        PARAMS ((tree, rtx, rtx));
 static rtx expand_nl_handler_label     PARAMS ((rtx, rtx));
@@ -1307,13 +1310,8 @@ expand_asm (body)
    Returns TRUE if all went well; FALSE if an error occurred.  */
 
 bool
-parse_output_constraint (constraint_p, 
-                        operand_num,
-                        ninputs,
-                        noutputs,
-                        allows_mem, 
-                        allows_reg, 
-                        is_inout)
+parse_output_constraint (constraint_p, operand_num, ninputs, noutputs,
+                        allows_mem, allows_reg, is_inout)
      const char **constraint_p;
      int operand_num;
      int ninputs;
@@ -1444,6 +1442,131 @@ parse_output_constraint (constraint_p,
   return true;
 }
 
+/* Similar, but for input constraints.  */
+
+static bool
+parse_input_constraint (constraint_p, input_num, ninputs, noutputs, ninout,
+                       constraints, allows_mem, allows_reg)
+     const char **constraint_p;
+     int input_num;
+     int ninputs;
+     int noutputs;
+     int ninout;
+     const char * const * constraints;
+     bool *allows_mem;
+     bool *allows_reg;
+{
+  const char *constraint = *constraint_p;
+  const char *orig_constraint = constraint;
+  size_t c_len = strlen (constraint);
+  size_t j;
+
+  /* Assume the constraint doesn't allow the use of either
+     a register or memory.  */
+  *allows_mem = false;
+  *allows_reg = false;
+
+  /* Make sure constraint has neither `=', `+', nor '&'.  */
+
+  for (j = 0; j < c_len; j++)
+    switch (constraint[j])
+      {
+      case '+':  case '=':  case '&':
+       if (constraint == orig_constraint)
+         {
+           error ("input operand constraint contains `%c'", constraint[j]);
+           return false;
+         }
+       break;
+
+      case '%':
+       if (constraint == orig_constraint
+           && input_num + 1 == ninputs - ninout)
+         {
+           error ("`%%' constraint used with last operand");
+           return false;
+         }
+       break;
+
+      case 'V':  case 'm':  case 'o':
+       *allows_mem = true;
+       break;
+
+      case '<':  case '>':
+      case '?':  case '!':  case '*':  case '#':
+      case 'E':  case 'F':  case 'G':  case 'H':
+      case 's':  case 'i':  case 'n':
+      case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
+      case 'N':  case 'O':  case 'P':  case ',':
+       break;
+
+       /* Whether or not a numeric constraint allows a register is
+          decided by the matching constraint, and so there is no need
+          to do anything special with them.  We must handle them in
+          the default case, so that we don't unnecessarily force
+          operands to memory.  */
+      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;
+
+         match = strtoul (constraint + j, &end, 10);
+         if (match >= (unsigned long) noutputs)
+           {
+             error ("matching constraint references invalid operand number");
+             return false;
+           }
+
+         /* 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];
+             *constraint_p = constraint;
+             c_len = strlen (constraint);
+             j = 0;
+             break;
+           }
+         else
+           j = end - constraint;
+       }
+       /* Fall through.  */
+
+      case 'p':  case 'r':
+       *allows_reg = true;
+       break;
+
+      case 'g':  case 'X':
+       *allows_reg = true;
+       *allows_mem = true;
+       break;
+
+      default:
+       if (! ISALPHA (constraint[j]))
+         {
+           error ("invalid punctuation `%c' in constraint", constraint[j]);
+           return false;
+         }
+       if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
+         *allows_reg = true;
+#ifdef EXTRA_CONSTRAINT
+       else
+         {
+           /* Otherwise we can't assume anything about the nature of
+              the constraint except that it isn't purely registers.
+              Treat it like "g" and hope for the best.  */
+           *allows_reg = true;
+           *allows_mem = true;
+         }
+#endif
+       break;
+      }
+
+  return true;
+}
+
 /* Generate RTL for an asm statement with arguments.
    STRING is the instruction template.
    OUTPUTS is a list of output arguments (lvalues); INPUTS a list of inputs.
@@ -1472,7 +1595,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   rtx body;
   int ninputs = list_length (inputs);
   int noutputs = list_length (outputs);
-  int ninout = 0;
+  int ninout;
   int nclobbers;
   tree tail;
   int i;
@@ -1524,10 +1647,15 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   last_expr_type = 0;
 
+  /* First pass over inputs and outputs checks validity and sets
+     mark_addressable if needed.  */
+
+  ninout = 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;
@@ -1536,22 +1664,67 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       if (type == error_mark_node)
        return;
 
-      /* Make sure constraint has `=' and does not have `+'.  Also, see
-        if it allows any register.  Be liberal on the latter test, since
-        the worst that happens if we get it wrong is we issue an error
-        message.  */
-
       /* Try to parse the output constraint.  If that fails, there's
         no point in going further.  */
-      if (!parse_output_constraint (&constraints[i],
-                                   i,
-                                   ninputs,
-                                   noutputs,
-                                   &allows_mem,
-                                   &allows_reg,
-                                   &is_inout))
+      constraint = constraints[i];
+      if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                   &allows_mem, &allows_reg, &is_inout))
+       return;
+
+      if (! allows_reg
+         && (allows_mem
+             || is_inout
+             || (DECL_P (val)
+                 && GET_CODE (DECL_RTL (val)) == REG
+                 && GET_MODE (DECL_RTL (val)) != TYPE_MODE (type))))
+       mark_addressable (val);
+
+      if (is_inout)
+       ninout++;
+    }
+
+  ninputs += ninout;
+  if (ninputs + noutputs > MAX_RECOG_OPERANDS)
+    {
+      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
+      return;
+    }
+
+  for (i = 0, tail = inputs; tail; i++, tail = TREE_CHAIN (tail))
+    {
+      bool allows_reg, allows_mem;
+      const char *constraint;
+
+      /* If there's an erroneous arg, emit no insn, because the ASM_INPUT
+        would get VOIDmode and that could cause a crash in reload.  */
+      if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
        return;
 
+      constraint = constraints[i + noutputs];
+      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                   constraints, &allows_mem, &allows_reg))
+       return;
+
+      if (! allows_reg && allows_mem)
+       mark_addressable (TREE_VALUE (tail));
+    }
+
+  /* Second pass evaluates arguments.  */
+
+  ninout = 0;
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+    {
+      tree val = TREE_VALUE (tail);
+      tree type = TREE_TYPE (val);
+      bool is_inout;
+      bool allows_reg;
+      bool allows_mem;
+
+      if (!parse_output_constraint (&constraints[i], i, ninputs,
+                                   noutputs, &allows_mem, &allows_reg,
+                                   &is_inout))
+       abort ();
+
       /* If an output operand is not a decl or indirect ref and our constraint
         allows a register, make a temporary to act as an intermediate.
         Make the asm insn write into that, then our caller will copy it to
@@ -1569,12 +1742,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
          || ! allows_reg
          || is_inout)
        {
-         if (! allows_reg)
-           mark_addressable (TREE_VALUE (tail));
-
-         output_rtx[i]
-           = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
-                          EXPAND_WRITE);
+         output_rtx[i] = expand_expr (val, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
          if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
            error ("output number %d not directly addressable", i);
@@ -1597,18 +1765,11 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       if (is_inout)
        {
-         inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
+         inout_mode[ninout] = TYPE_MODE (type);
          inout_opnum[ninout++] = i;
        }
     }
 
-  ninputs += ninout;
-  if (ninputs + noutputs > MAX_RECOG_OPERANDS)
-    {
-      error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
-      return;
-    }
-
   /* Make vectors for the expression-rtx, constraint strings,
      and named operands.  */
 
@@ -1628,154 +1789,40 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
   for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), ++i)
     {
-      int j;
-      int allows_reg = 0, allows_mem = 0;
-      const char *constraint, *orig_constraint;
-      int c_len;
+      bool allows_reg, allows_mem;
+      const char *constraint;
+      tree val, type;
       rtx op;
 
-      /* If there's an erroneous arg, emit no insn,
-        because the ASM_INPUT would get VOIDmode
-        and that could cause a crash in reload.  */
-      if (TREE_TYPE (TREE_VALUE (tail)) == error_mark_node)
-       return;
-
-      /* ??? Can this happen, and does the error message make any sense? */
-      if (TREE_PURPOSE (tail) == NULL_TREE)
-       {
-         error ("hard register `%s' listed as input operand to `asm'",
-                TREE_STRING_POINTER (TREE_VALUE (tail)) );
-         return;
-       }
-
-      orig_constraint = constraint = constraints[i + noutputs];
-      c_len = strlen (constraint);
-
-      /* Make sure constraint has neither `=', `+', nor '&'.  */
-
-      for (j = 0; j < c_len; j++)
-       switch (constraint[j])
-         {
-         case '+':  case '=':  case '&':
-           if (constraint == orig_constraint)
-             {
-               error ("input operand constraint contains `%c'",
-                      constraint[j]);
-               return;
-             }
-           break;
-
-         case '%':
-           if (constraint == orig_constraint
-               && i + 1 == ninputs - ninout)
-             {
-               error ("`%%' constraint used with last operand");
-               return;
-             }
-           break;
-
-         case 'V':  case 'm':  case 'o':
-           allows_mem = 1;
-           break;
-
-         case '<':  case '>':
-         case '?':  case '!':  case '*':  case '#':
-         case 'E':  case 'F':  case 'G':  case 'H':
-         case 's':  case 'i':  case 'n':
-         case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
-         case 'N':  case 'O':  case 'P':  case ',':
-           break;
-
-           /* Whether or not a numeric constraint allows a register is
-              decided by the matching constraint, and so there is no need
-              to do anything special with them.  We must handle them in
-              the default case, so that we don't unnecessarily force
-              operands to memory.  */
-         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;
-
-             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':
-           allows_reg = 1;
-           break;
-
-         case 'g':  case 'X':
-           allows_reg = 1;
-           allows_mem = 1;
-           break;
-
-         default:
-           if (! ISALPHA (constraint[j]))
-             {
-               error ("invalid punctuation `%c' in constraint",
-                      constraint[j]);
-               return;
-             }
-           if (REG_CLASS_FROM_LETTER (constraint[j]) != NO_REGS)
-             allows_reg = 1;
-#ifdef EXTRA_CONSTRAINT
-           else
-             {
-               /* Otherwise we can't assume anything about the nature of
-                  the constraint except that it isn't purely registers.
-                  Treat it like "g" and hope for the best.  */
-               allows_reg = 1;
-               allows_mem = 1;
-             }
-#endif
-           break;
-         }
+      constraint = constraints[i + noutputs];
+      if (! parse_input_constraint (&constraint, i, ninputs, noutputs, ninout,
+                                   constraints, &allows_mem, &allows_reg))
+       abort ();
 
-      if (! allows_reg && allows_mem)
-       mark_addressable (TREE_VALUE (tail));
+      generating_concat_p = 0;
 
-      op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
+      val = TREE_VALUE (tail);
+      type = TREE_TYPE (val);
+      op = expand_expr (val, NULL_RTX, VOIDmode, 0);
 
       /* Never pass a CONCAT to an ASM.  */
-      generating_concat_p = 0;
       if (GET_CODE (op) == CONCAT)
        op = force_reg (GET_MODE (op), op);
 
       if (asm_operand_ok (op, constraint) <= 0)
        {
          if (allows_reg)
-           op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
+           op = force_reg (TYPE_MODE (type), op);
          else if (!allows_mem)
            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);
+           op = force_const_mem (TYPE_MODE (type), op);
          else if (GET_CODE (op) == REG
                   || GET_CODE (op) == SUBREG
                   || GET_CODE (op) == ADDRESSOF
                   || GET_CODE (op) == CONCAT)
            {
-             tree type = TREE_TYPE (TREE_VALUE (tail));
              tree qual_type = build_qualified_type (type,
                                                     (TYPE_QUALS (type)
                                                      | TYPE_QUAL_CONST));
@@ -1786,9 +1833,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            }
 
          else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
-           /* We won't recognize volatile memory as available a
-              memory_operand at this point.  Ignore it.  */
-           ;
+           {
+             /* We won't recognize volatile memory as available a
+                memory_operand at this point.  Ignore it.  */
+           }
          else if (queued_subexp_p (op))
            ;
          else
@@ -1798,12 +1846,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
            warning ("asm operand %d probably doesn't match constraints",
                     i + noutputs);
        }
+
       generating_concat_p = old_generating_concat_p;
       ASM_OPERANDS_INPUT (body, i) = op;
 
       ASM_OPERANDS_INPUT_CONSTRAINT_EXP (body, i)
-       = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                            orig_constraint);
+       = gen_rtx_ASM_INPUT (TYPE_MODE (type), constraints[i + noutputs]);
     }
 
   /* Protect all the operands from the queue now that they have all been
diff --git a/gcc/testsuite/gcc.c-torture/compile/20011205-1.c b/gcc/testsuite/gcc.c-torture/compile/20011205-1.c
new file mode 100644 (file)
index 0000000..ffc5ac4
--- /dev/null
@@ -0,0 +1,10 @@
+/* Failure to mark_addressable all operands before evaluation means we
+   don't set up the proper temporaries, which leaves us with an asm that
+   doesn't match its contraints.  */
+
+long foo()
+{
+  long x;
+  asm("" : "=r"(x) : "m"(x));
+  return x;
+}