re PR middle-end/44492 (auto-inc-dec pushes PRE_MODIFY/PRE_INC into inline asm operands)
authorJakub Jelinek <jakub@redhat.com>
Thu, 24 Jun 2010 17:48:16 +0000 (19:48 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 24 Jun 2010 17:48:16 +0000 (19:48 +0200)
PR middle-end/44492
* recog.h (struct recog_data): Add is_asm field.
* recog.c (asm_operand_ok, constrain_operands): If neither < nor > is
present in constraints of inline-asm operand and memory operand
contains {PRE,POST}_{INC,DEC,MODIFY}, return 0.
(extract_insn): Initialize recog_data.is_asm.
* doc/md.texi (Constraints): Document operand side-effect rules.

* g++.dg/torture/pr44492.C: New test.

From-SVN: r161328

gcc/ChangeLog
gcc/doc/md.texi
gcc/recog.c
gcc/recog.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr44492.C [new file with mode: 0644]

index cb16414..b6e3eed 100644 (file)
@@ -1,3 +1,13 @@
+2010-06-24  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/44492
+       * recog.h (struct recog_data): Add is_asm field.
+       * recog.c (asm_operand_ok, constrain_operands): If neither < nor > is
+       present in constraints of inline-asm operand and memory operand
+       contains {PRE,POST}_{INC,DEC,MODIFY}, return 0.
+       (extract_insn): Initialize recog_data.is_asm.
+       * doc/md.texi (Constraints): Document operand side-effect rules.
+
 2010-06-24  Andi Kleen  <ak@linux.intel.com>
 
        * c-parser.c (c_parser_conditional_expression):
index c37bb03..46bd4f6 100644 (file)
@@ -1052,6 +1052,10 @@ an operand may be in a register, and which kinds of register; whether the
 operand can be a memory reference, and which kinds of address; whether the
 operand may be an immediate constant, and which possible values it may
 have.  Constraints can also require two operands to match.
+Side-effects aren't allowed in operands of inline @code{asm}, unless
+@samp{<} or @samp{>} constraints are used, because there is no guarantee
+that the side-effects will happen exactly once in an instruction that can update
+the addressing register.
 
 @ifset INTERNALS
 @menu
@@ -1129,12 +1133,21 @@ would fit the @samp{m} constraint but not the @samp{o} constraint.
 @cindex @samp{<} in constraint
 @item @samp{<}
 A memory operand with autodecrement addressing (either predecrement or
-postdecrement) is allowed.
+postdecrement) is allowed.  In inline @code{asm} this constraint is only
+allowed if the operand is used exactly once in an instruction that can
+handle the side-effects.  Not using an operand with @samp{<} in constraint
+string in the inline @code{asm} pattern at all or using it in multiple
+instructions isn't valid, because the side-effects wouldn't be performed
+or would be performed more than once.  Furthermore, on some targets
+the operand with @samp{<} in constraint string must be accompanied by
+special instruction suffixes like @code{%U0} instruction suffix on PowerPC
+or @code{%P0} on IA-64.
 
 @cindex @samp{>} in constraint
 @item @samp{>}
 A memory operand with autoincrement addressing (either preincrement or
-postincrement) is allowed.
+postincrement) is allowed.  In inline @code{asm} the same restrictions
+as for @samp{<} apply.
 
 @cindex @samp{r} in constraint
 @cindex registers in constraints
index 1847c23..43f901f 100644 (file)
@@ -1601,6 +1601,9 @@ int
 asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 {
   int result = 0;
+#ifdef AUTO_INC_DEC
+  bool incdec_ok = false;
+#endif
 
   /* Use constrain_operands after reload.  */
   gcc_assert (!reload_completed);
@@ -1608,7 +1611,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
   /* Empty constraint string is the same as "X,...,X", i.e. X for as
      many alternatives as required to match the other operands.  */
   if (*constraint == '\0')
-    return 1;
+    result = 1;
 
   while (*constraint)
     {
@@ -1685,6 +1688,9 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
                  || GET_CODE (XEXP (op, 0)) == PRE_DEC
                  || GET_CODE (XEXP (op, 0)) == POST_DEC))
            result = 1;
+#ifdef AUTO_INC_DEC
+         incdec_ok = true;
+#endif
          break;
 
        case '>':
@@ -1693,6 +1699,9 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
                  || GET_CODE (XEXP (op, 0)) == PRE_INC
                  || GET_CODE (XEXP (op, 0)) == POST_INC))
            result = 1;
+#ifdef AUTO_INC_DEC
+         incdec_ok = true;
+#endif
          break;
 
        case 'E':
@@ -1814,6 +1823,23 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
        return 0;
     }
 
+#ifdef AUTO_INC_DEC
+  /* For operands without < or > constraints reject side-effects.  */
+  if (!incdec_ok && result && MEM_P (op))
+    switch (GET_CODE (XEXP (op, 0)))
+      {
+      case PRE_INC:
+      case POST_INC:
+      case PRE_DEC:
+      case POST_DEC:
+      case PRE_MODIFY:
+      case POST_MODIFY:
+       return 0;
+      default:
+       break;
+      }
+#endif
+
   return result;
 }
 \f
@@ -2039,6 +2065,7 @@ extract_insn (rtx insn)
   recog_data.n_operands = 0;
   recog_data.n_alternatives = 0;
   recog_data.n_dups = 0;
+  recog_data.is_asm = false;
 
   switch (GET_CODE (body))
     {
@@ -2085,6 +2112,7 @@ extract_insn (rtx insn)
              while (*p)
                recog_data.n_alternatives += (*p++ == ',');
            }
+         recog_data.is_asm = true;
          break;
        }
       fatal_insn_not_found (insn);
@@ -2699,6 +2727,30 @@ constrain_operands (int strict)
                    = recog_data.operand[funny_match[funny_match_index].this_op];
                }
 
+#ifdef AUTO_INC_DEC
+             /* For operands without < or > constraints reject side-effects.  */
+             if (recog_data.is_asm)
+               {
+                 for (opno = 0; opno < recog_data.n_operands; opno++)
+                   if (MEM_P (recog_data.operand[opno]))
+                     switch (GET_CODE (XEXP (recog_data.operand[opno], 0)))
+                       {
+                       case PRE_INC:
+                       case POST_INC:
+                       case PRE_DEC:
+                       case POST_DEC:
+                       case PRE_MODIFY:
+                       case POST_MODIFY:
+                         if (strchr (recog_data.constraints[opno], '<') == NULL
+                             || strchr (recog_data.constraints[opno], '>')
+                                == NULL)
+                           return 0;
+                         break;
+                       default:
+                         break;
+                       }
+               }
+#endif
              return 1;
            }
        }
index c2972ab..71dba91 100644 (file)
@@ -230,6 +230,9 @@ struct recog_data
   /* The number of alternatives in the constraints for the insn.  */
   char n_alternatives;
 
+  /* True if insn is ASM_OPERANDS.  */
+  bool is_asm;
+
   /* Specifies whether an insn alternative is enabled using the
      `enabled' attribute in the insn pattern definition.  For back
      ends not using the `enabled' attribute the array fields are
index 351dcd8..ef242f6 100644 (file)
@@ -1,3 +1,8 @@
+2010-06-24  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/44492
+       * g++.dg/torture/pr44492.C: New test.
+
 2010-06-24  Andi Kleen  <ak@linux.intel.com>
 
         * c-c++-common/warn-omitted-condop.c: New.
diff --git a/gcc/testsuite/g++.dg/torture/pr44492.C b/gcc/testsuite/g++.dg/torture/pr44492.C
new file mode 100644 (file)
index 0000000..4166924
--- /dev/null
@@ -0,0 +1,31 @@
+// PR middle-end/44492
+// { dg-do run }
+
+struct T { unsigned long p; };
+struct S { T a, b, c; unsigned d; };
+
+__attribute__((noinline))
+void
+bar (const T &x, const T &y)
+{
+  if (x.p != 0x2348 || y.p != 0x2346)
+    __builtin_abort ();
+}
+
+__attribute__((noinline))
+void
+foo (S &s, T e)
+{
+  unsigned long a = e.p;
+  unsigned long b = s.b.p;
+  __asm__ volatile ("" : : "rm" (a), "rm" (b));
+  bar (e, s.b);
+}
+
+int
+main ()
+{
+  S s = { { 0x2345 }, { 0x2346 }, { 0x2347 }, 6 };
+  T t = { 0x2348 };
+  foo (s, t);
+}