]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
inline-asm: Fix ICE with bitfields in "m" operands [PR100785]
authorJakub Jelinek <jakub@redhat.com>
Mon, 21 Jun 2021 11:30:42 +0000 (13:30 +0200)
committerJakub Jelinek <jakub@redhat.com>
Wed, 23 Jun 2021 13:13:24 +0000 (15:13 +0200)
Bitfields, while they live in memory, aren't something inline-asm can easily
operate on.
For C and "=m" or "+m", we were diagnosing bitfields in the past in the
FE, where c_mark_addressable had:
      case COMPONENT_REF:
        if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
          {
            error
              ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1));
            return false;
          }
but that check got moved in GCC 6 to build_unary_op instead and now we
emit an error during expansion and ICE afterwards (i.e. error-recovery).
For "m" it used to be diagnosed in c_mark_addressable too, but since
GCC 6 it is ice-on-invalid.
For C++, this was never diagnosed in the FE, but used to be diagnosed
in the gimplifier and/or during expansion before 4.8.

The following patch does multiple things:
1) diagnoses it in the FEs
2) simplifies during expansion the inline asm if any errors have been
   reported (similarly how e.g. vregs pass if it detects errors on
   inline-asm either deletes them or simplifies to bare minimum -
   just labels), so that we don't have error-recovery ICEs there

2021-06-11  Jakub Jelinek  <jakub@redhat.com>

PR inline-asm/100785
gcc/
* cfgexpand.c (expand_asm_stmt): If errors are emitted,
remove all inputs, outputs and clobbers from the asm and
set template to "".
gcc/c/
* c-typeck.c (c_mark_addressable): Diagnose trying to make
bit-fields addressable.
gcc/cp/
* typeck.c (cxx_mark_addressable): Diagnose trying to make
bit-fields addressable.
gcc/testsuite/
* c-c++-common/pr100785.c: New test.

(cherry picked from commit 644c2cc5f2c09506a7bfef293a7f90efa8d7e5fa)

gcc/c/c-typeck.c
gcc/cfgexpand.c
gcc/cp/typeck.c
gcc/testsuite/c-c++-common/pr100785.c [new file with mode: 0644]

index 917e670ddd71288171c285ed7aedfdee4b3d05af..7b84f3e645661e5ad91bc4406c4bdc332d0b3814 100644 (file)
@@ -5033,8 +5033,17 @@ c_mark_addressable (tree exp, bool array_ref_p)
            && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
            && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
          return true;
-       /* FALLTHRU */
+       x = TREE_OPERAND (x, 0);
+       break;
+
       case COMPONENT_REF:
+       if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
+         {
+           error ("cannot take address of bit-field %qD",
+                  TREE_OPERAND (x, 1));
+           return false;
+         }
+       /* FALLTHRU */
       case ADDR_EXPR:
       case ARRAY_REF:
       case REALPART_EXPR:
index c221b4165caf1a7f7b08ddcacc2fad9910159ae4..0c26337bfa34df305ddd936669d5c9ed0160f143 100644 (file)
@@ -3076,6 +3076,7 @@ expand_asm_stmt (gasm *stmt)
   unsigned ninputs = gimple_asm_ninputs (stmt);
   unsigned nlabels = gimple_asm_nlabels (stmt);
   unsigned i;
+  bool error_seen = false;
 
   /* ??? Diagnose during gimplification?  */
   if (ninputs + noutputs + nlabels > MAX_RECOG_OPERANDS)
@@ -3134,6 +3135,7 @@ expand_asm_stmt (gasm *stmt)
                {
                  /* ??? Diagnose during gimplification?  */
                  error ("unknown register name %qs in %<asm%>", regname);
+                 error_seen = true;
                }
              else if (j == -4)
                {
@@ -3196,7 +3198,10 @@ expand_asm_stmt (gasm *stmt)
                && REG_P (DECL_RTL (output_tvec[j]))
                && HARD_REGISTER_P (DECL_RTL (output_tvec[j]))
                && output_hregno == REGNO (DECL_RTL (output_tvec[j])))
-             error ("invalid hard register usage between output operands");
+             {
+               error ("invalid hard register usage between output operands");
+               error_seen = true;
+             }
 
          /* Verify matching constraint operands use the same hard register
             and that the non-matching constraint operands do not use the same
@@ -3219,13 +3224,19 @@ expand_asm_stmt (gasm *stmt)
                  }
                if (i == match
                    && output_hregno != input_hregno)
-                 error ("invalid hard register usage between output operand "
-                        "and matching constraint operand");
+                 {
+                   error ("invalid hard register usage between output "
+                          "operand and matching constraint operand");
+                   error_seen = true;
+                 }
                else if (early_clobber_p
                         && i != match
                         && output_hregno == input_hregno)
-                 error ("invalid hard register usage between earlyclobber "
-                        "operand and input operand");
+                 {
+                   error ("invalid hard register usage between "
+                          "earlyclobber operand and input operand");
+                   error_seen = true;
+                 }
              }
        }
 
@@ -3301,7 +3312,10 @@ expand_asm_stmt (gasm *stmt)
            op = validize_mem (op);
 
          if (! allows_reg && !MEM_P (op))
-           error ("output number %d not directly addressable", i);
+           {
+             error ("output number %d not directly addressable", i);
+             error_seen = true;
+           }
          if ((! allows_mem && MEM_P (op) && GET_MODE (op) != BLKmode)
              || GET_CODE (op) == CONCAT)
            {
@@ -3341,6 +3355,19 @@ expand_asm_stmt (gasm *stmt)
        inout_opnum.safe_push (i);
     }
 
+  const char *str = gimple_asm_string (stmt);
+  if (error_seen)
+    {
+      ninputs = 0;
+      noutputs = 0;
+      inout_opnum.truncate (0);
+      output_rvec.truncate (0);
+      clobber_rvec.truncate (0);
+      constraints.truncate (0);
+      CLEAR_HARD_REG_SET (clobbered_regs);
+      str = "";
+    }
+
   auto_vec<rtx, MAX_RECOG_OPERANDS> input_rvec;
   auto_vec<machine_mode, MAX_RECOG_OPERANDS> input_mode;
 
@@ -3399,7 +3426,7 @@ expand_asm_stmt (gasm *stmt)
     }
 
   /* For in-out operands, copy output rtx to input rtx.  */
-  unsigned ninout = inout_opnum.length();
+  unsigned ninout = inout_opnum.length ();
   for (i = 0; i < ninout; i++)
     {
       int j = inout_opnum[i];
@@ -3453,7 +3480,7 @@ expand_asm_stmt (gasm *stmt)
 
   rtx body = gen_rtx_ASM_OPERANDS ((noutputs == 0 ? VOIDmode
                                    : GET_MODE (output_rvec[0])),
-                                  ggc_strdup (gimple_asm_string (stmt)),
+                                  ggc_strdup (str),
                                   "", 0, argvec, constraintvec,
                                   labelvec, locus);
   MEM_VOLATILE_P (body) = gimple_asm_volatile_p (stmt);
index cce26b89cdec839f7bc17a5f0404a1c9f6ef0625..1b68c53b831aa36c486c261be90a5604a6092d47 100644 (file)
@@ -7081,9 +7081,14 @@ cxx_mark_addressable (tree exp, bool array_ref_p)
            && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
            && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
          return true;
+       x = TREE_OPERAND (x, 0);
+       break;
+
+      case COMPONENT_REF:
+       if (bitfield_p (x))
+         error ("attempt to take address of bit-field");
        /* FALLTHRU */
       case ADDR_EXPR:
-      case COMPONENT_REF:
       case ARRAY_REF:
       case REALPART_EXPR:
       case IMAGPART_EXPR:
diff --git a/gcc/testsuite/c-c++-common/pr100785.c b/gcc/testsuite/c-c++-common/pr100785.c
new file mode 100644 (file)
index 0000000..a3cd4cf
--- /dev/null
@@ -0,0 +1,21 @@
+/* PR inline-asm/100785 */
+
+struct S { int a : 1; };
+
+void
+foo (struct S *x)
+{
+  __asm__ ("" : "+m" (x->a));  /* { dg-error "address of bit-field" } */
+}                              /* { dg-error "invalid lvalue in 'asm' output 0" "" { target c } .-1 } */
+                               /* { dg-error "memory input 1 is not directly addressable" "" { target c } .-2 } */
+void
+bar (struct S *x)
+{
+  __asm__ ("" : "=m" (x->a));  /* { dg-error "address of bit-field" } */
+}                              /* { dg-error "invalid lvalue in 'asm' output 0" "" { target c } .-1 } */
+
+void
+baz (struct S *x)
+{
+  __asm__ ("" : : "m" (x->a)); /* { dg-error "address of bit-field" } */
+}                              /* { dg-error "memory input 0 is not directly addressable" "" { target c } .-1 } */