re PR inline-asm/15740 (ICE caused by a memory operand in an asm statement)
authorRichard Henderson <rth@redhat.com>
Wed, 29 Dec 2004 01:22:15 +0000 (17:22 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 29 Dec 2004 01:22:15 +0000 (17:22 -0800)
PR inline-asm/15740
        * gimplify.c (gimplify_asm_expr): Move resolve asm names ...
        * c-typeck.c (build_asm_expr): ... here.  Validate input
        constraints.  Mark memory inputs addressable.

        * semantics.c (finish_asm_stmt): Resolve asm names.  Validate input
        constraints.  Mark memory inputs addressable.

From-SVN: r92693

gcc/ChangeLog
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/gimplify.c
gcc/testsuite/g++.dg/opt/asm2.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/asm-9.c [new file with mode: 0644]

index 7b44126c745081c4c6da1ab827bae1b61f7c875a..d89c8923645436f2fad9631ac0079217a416b0b1 100644 (file)
@@ -1,3 +1,10 @@
+2004-12-28  Richard Henderson  <rth@redhat.com>
+
+       PR inline-asm/15740
+       * gimplify.c (gimplify_asm_expr): Move resolve asm names ...
+       * c-typeck.c (build_asm_expr): ... here.  Validate input
+       constraints.  Mark memory inputs addressable.
+
 2004-12-28  Hans-Peter Nilsson  <hp@bitrange.com>
 
        PR target/18321
index d2963b374545bcce6e4ace76b67b38330cf936d3..5eae3aa7d5ec5edca018333d3b94488ff8623c9d 100644 (file)
@@ -6287,47 +6287,74 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
   tree args;
   int i;
   const char *constraint;
+  const char **oconstraints;
   bool allows_mem, allows_reg, is_inout;
-  int ninputs;
-  int noutputs;
+  int ninputs, noutputs;
 
   ninputs = list_length (inputs);
   noutputs = list_length (outputs);
+  oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
+
+  string = resolve_asm_operand_names (string, outputs, inputs);
 
   /* Remove output conversions that change the type but not the mode.  */
   for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
     {
       tree output = TREE_VALUE (tail);
+
+      /* ??? Really, this should not be here.  Users should be using a
+        proper lvalue, dammit.  But there's a long history of using casts
+        in the output operands.  In cases like longlong.h, this becomes a
+        primitive form of typechecking -- if the cast can be removed, then
+        the output operand had a type of the proper width; otherwise we'll
+        get an error.  Gross, but ...  */
       STRIP_NOPS (output);
-      TREE_VALUE (tail) = output;
-      lvalue_or_else (output, lv_asm);
+
+      if (!lvalue_or_else (output, lv_asm))
+       output = error_mark_node;
 
       constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+      oconstraints[i] = constraint;
 
-      if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
-                                    &allows_mem, &allows_reg, &is_inout))
-        {
-          /* By marking this operand as erroneous, we will not try
-          to process this operand again in expand_asm_operands.  */
-          TREE_VALUE (tail) = error_mark_node;
-          continue;
-        }
+      if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                  &allows_mem, &allows_reg, &is_inout))
+       {
+         /* If the operand is going to end up in memory,
+            mark it addressable.  */
+         if (!allows_reg && !c_mark_addressable (output))
+           output = error_mark_node;
+       }
+      else
+        output = error_mark_node;
 
-      /* If the operand is a DECL that is going to end up in
-        memory, assume it is addressable.  This is a bit more
-        conservative than it would ideally be; the exact test is
-        buried deep in expand_asm_operands and depends on the
-        DECL_RTL for the OPERAND -- which we don't have at this
-        point.  */
-      if (!allows_reg && DECL_P (output))
-        c_mark_addressable (output);
+      TREE_VALUE (tail) = output;
     }
 
   /* Perform default conversions on array and function inputs.
      Don't do this for other types as it would screw up operands
      expected to be in memory.  */
-  for (tail = inputs; tail; tail = TREE_CHAIN (tail))
-    TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
+  for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
+    {
+      tree input;
+
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+      input = TREE_VALUE (tail);
+
+      input = default_function_array_conversion (input);
+
+      if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+                                 oconstraints, &allows_mem, &allows_reg))
+       {
+         /* If the operand is going to end up in memory,
+            mark it addressable.  */
+         if (!allows_reg && allows_mem && !c_mark_addressable (input))
+           input = error_mark_node;
+       }
+      else
+       input = error_mark_node;
+
+      TREE_VALUE (tail) = input;
+    }
 
   args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
 
@@ -6337,6 +6364,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
       ASM_VOLATILE_P (args) = 1;
       ASM_INPUT_P (args) = 1;
     }
+
   return args;
 }
 \f
index 622a0012a13ba1fdd9a2688084c8dac0608c2ba5..9e96120e8083bdea8c3ffc0ae699eb1832741ab3 100644 (file)
@@ -1,3 +1,9 @@
+2004-12-28  Richard Henderson  <rth@redhat.com>
+
+       PR inline-asm/15740
+       * semantics.c (finish_asm_stmt): Resolve asm names.  Validate input
+       constraints.  Mark memory inputs addressable.
+
 2004-12-27  Jason Merrill  <jason@redhat.com>
 
        * decl.c (expand_static_init): Don't use shortcut if
index ab1c028ff5d53885d82f2f0fe49f5ba674bf94cf..b34de199adb045bf66f99983bf79fbd229d2644a 100644 (file)
@@ -1139,62 +1139,80 @@ finish_asm_stmt (int volatile_p, tree string, tree output_operands,
 
   if (!processing_template_decl)
     {
+      int ninputs, noutputs;
+      const char *constraint;
+      const char **oconstraints;
+      bool allows_mem, allows_reg, is_inout;
+      tree operand;
       int i;
-      int ninputs;
-      int noutputs;
 
-      for (t = input_operands; t; t = TREE_CHAIN (t))
+      ninputs = list_length (input_operands);
+      noutputs = list_length (output_operands);
+      oconstraints = (const char **) alloca (noutputs * sizeof (char *));
+
+      string = resolve_asm_operand_names (string, output_operands,
+                                         input_operands);
+
+      for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
        {
-         tree converted_operand 
-           = decay_conversion (TREE_VALUE (t)); 
-         
+         operand = TREE_VALUE (t);
+
+         /* ??? Really, this should not be here.  Users should be using a
+            proper lvalue, dammit.  But there's a long history of using
+            casts in the output operands.  In cases like longlong.h, this
+            becomes a primitive form of typechecking -- if the cast can be
+            removed, then the output operand had a type of the proper width;
+            otherwise we'll get an error.  Gross, but ...  */
+         STRIP_NOPS (operand);
+
+         if (!lvalue_or_else (operand, lv_asm))
+           operand = error_mark_node;
+
+         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+         oconstraints[i] = constraint;
+
+         if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                      &allows_mem, &allows_reg, &is_inout))
+           {
+             /* If the operand is going to end up in memory,
+                mark it addressable.  */
+             if (!allows_reg && !cxx_mark_addressable (operand))
+               operand = error_mark_node;
+           }
+         else
+           operand = error_mark_node;
+
+         TREE_VALUE (t) = operand;
+       }
+
+      for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
+       {
+         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+         operand = decay_conversion (TREE_VALUE (t)); 
+
          /* If the type of the operand hasn't been determined (e.g.,
             because it involves an overloaded function), then issue
             an error message.  There's no context available to
             resolve the overloading.  */
-         if (TREE_TYPE (converted_operand) == unknown_type_node)
+         if (TREE_TYPE (operand) == unknown_type_node)
            {
              error ("type of asm operand %qE could not be determined", 
                      TREE_VALUE (t));
-             converted_operand = error_mark_node;
+             operand = error_mark_node;
            }
-         TREE_VALUE (t) = converted_operand;
-       }
-
-      ninputs = list_length (input_operands);
-      noutputs = list_length (output_operands);
-
-      for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
-       {
-         bool allows_mem;
-         bool allows_reg;
-         bool is_inout;
-         const char *constraint;
-         tree operand;
 
-         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
-         operand = TREE_VALUE (t);
-
-         if (!parse_output_constraint (&constraint,
-                                       i, ninputs, noutputs,
-                                       &allows_mem,
-                                       &allows_reg,
-                                       &is_inout))
+         if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+                                     oconstraints, &allows_mem, &allows_reg))
            {
-             /* By marking this operand as erroneous, we will not try
-                to process this operand again in expand_asm_operands.  */
-             TREE_VALUE (t) = error_mark_node;
-             continue;
+             /* If the operand is going to end up in memory,
+                mark it addressable.  */
+             if (!allows_reg && allows_mem && !cxx_mark_addressable (operand))
+               operand = error_mark_node;
            }
+         else
+           operand = error_mark_node;
 
-         /* If the operand is a DECL that is going to end up in
-            memory, assume it is addressable.  This is a bit more
-            conservative than it would ideally be; the exact test is
-            buried deep in expand_asm_operands and depends on the
-            DECL_RTL for the OPERAND -- which we don't have at this
-            point.  */
-         if (!allows_reg && DECL_P (operand))
-           cxx_mark_addressable (operand);
+         TREE_VALUE (t) = operand;
        }
     }
 
index f89b7207c14836ff69d4e7757ec81e12fd4b8ad3..ca3759769b133331ef42cefa728e2495df7f7a98 100644 (file)
@@ -3262,10 +3262,6 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
   bool allows_mem, allows_reg, is_inout;
   enum gimplify_status ret, tret;
 
-  ASM_STRING (expr)
-    = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
-                                ASM_INPUTS (expr));
-
   ret = GS_ALL_DONE;
   for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link))
     {
diff --git a/gcc/testsuite/g++.dg/opt/asm2.C b/gcc/testsuite/g++.dg/opt/asm2.C
new file mode 100644 (file)
index 0000000..4e32441
--- /dev/null
@@ -0,0 +1,11 @@
+/* PR inline-asm/15740 */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo(void)
+{
+  int a, b;
+  a = 1;
+  b = a + 1;
+  asm ("" : : "m" (a));
+}
diff --git a/gcc/testsuite/gcc.dg/asm-9.c b/gcc/testsuite/gcc.dg/asm-9.c
new file mode 100644 (file)
index 0000000..4e32441
--- /dev/null
@@ -0,0 +1,11 @@
+/* PR inline-asm/15740 */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+void foo(void)
+{
+  int a, b;
+  a = 1;
+  b = a + 1;
+  asm ("" : : "m" (a));
+}