This corrects an error in store_multiple_operation. We're only
generating the writeback version of the instruction on Thumb-1, so
that's where we must make sure the base register isn't also stored.

The ARMv7 manual is unfortunately not totally clear that this does in
fact produce unpredictable results; it seems to suggest that this is the
case only for the T2 encoding. Older documentation makes it clear.

Tested on arm-eabi{,mthumb}.


Bernd
        * config/arm/arm.c (store_multiple_sequence): Avoid cases where
        the base reg is stored iff compiling for Thumb1.

        * gcc.target/arm/pr49641.c: New test.

Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c        (revision 175906)
+++ gcc/config/arm/arm.c        (working copy)
@@ -9950,7 +9950,10 @@ store_multiple_sequence (rtx *operands,
          /* If it isn't an integer register, then we can't do this.  */
          if (unsorted_regs[i] < 0
              || (TARGET_THUMB1 && unsorted_regs[i] > LAST_LO_REGNUM)
-             || (TARGET_THUMB2 && unsorted_regs[i] == base_reg)
+             /* For Thumb1, we'll generate an instruction with update,
+                and the effects are unpredictable if the base reg is
+                stored.  */
+             || (TARGET_THUMB1 && unsorted_regs[i] == base_reg)
              || (TARGET_THUMB2 && unsorted_regs[i] == SP_REGNUM)
              || unsorted_regs[i] > 14)
            return 0;
Index: gcc/testsuite/gcc.target/arm/pr49641.c
===================================================================
--- gcc/testsuite/gcc.target/arm/pr49641.c      (revision 0)
+++ gcc/testsuite/gcc.target/arm/pr49641.c      (revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-final { scan-assembler-not "stmia\[\\t \]*r3!\[^\\n]*r3" } } */
+typedef struct {
+  void *t1, *t2, *t3;
+} z;
+extern volatile int y;
+static inline void foo(z *x) {
+  x->t1 = &x->t2;
+  x->t2 = ((void *)0);
+  x->t3 = &x->t1;
+}
+extern z v;
+void bar (void) {
+   y = 0;
+   foo(&v);
+}

Reply via email to