re PR target/64452 (ICE in avr-gcc when passing struct member to varargs function)
authorGeorg-Johann Lay <avr@gjlay.de>
Fri, 20 Feb 2015 10:30:24 +0000 (10:30 +0000)
committerGeorg-Johann Lay <gjl@gcc.gnu.org>
Fri, 20 Feb 2015 10:30:24 +0000 (10:30 +0000)
gcc/
PR target/64452
* config/avr/avr.md (pushhi_insn): New insn.
(push<mode>1): Push virtual regs in one chunk using pushhi1_insn.
gcc/testsuite/
PR target/64452
* gcc.target/avr/torture/pr64452.c: New test.

From-SVN: r220847

gcc/ChangeLog
gcc/config/avr/avr.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/avr/torture/pr64452.c [new file with mode: 0644]

index ff6df3df9f1441e08abfdec8fc61eefa0ce4318c..8d37e3534e7a2ba1dabf08b971cbce6f97c3c493 100644 (file)
@@ -1,3 +1,9 @@
+2015-02-20  Georg-Johann Lay  <avr@gjlay.de>
+
+       PR target/64452
+       * config/avr/avr.md (pushhi_insn): New insn.
+       (push<mode>1): Push virtual regs in one chunk using pushhi1_insn.
+
 2015-02-20  Bernd Schmidt  <bernds@codesourcery.com>
            Jakub Jelinek  <jakub@redhat.com>
 
index 5285a472e99cee3b8c06360e6de9077b1890a2d7..d6d930c74b68c31c0d165bf474f4e654f8cd9aa6 100644 (file)
        push __zero_reg__"
   [(set_attr "length" "1,1")])
 
+(define_insn "pushhi1_insn"
+  [(set (mem:HI (post_dec:HI (reg:HI REG_SP)))
+        (match_operand:HI 0 "register_operand" "r"))]
+  ""
+  "push %B0\;push %A0"
+  [(set_attr "length" "2")])
+
 ;; All modes for a multi-byte push.  We must include complex modes here too,
 ;; lest emit_single_push_insn "helpfully" create the auto-inc itself.
 (define_mode_iterator MPUSH
   [(match_operand:MPUSH 0 "" "")]
   ""
   {
-    int i;
-
-    // Avoid (subreg (mem)) for non-generic address spaces below.  Because
-    // of the poor addressing capabilities of these spaces it's better to
-    // load them in one chunk.  And it avoids PR61443.
-
     if (MEM_P (operands[0])
         && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[0])))
-      operands[0] = copy_to_mode_reg (<MODE>mode, operands[0]);
+      {
+        // Avoid (subreg (mem)) for non-generic address spaces.  Because
+        // of the poor addressing capabilities of these spaces it's better to
+        // load them in one chunk.  And it avoids PR61443.
+
+        operands[0] = copy_to_mode_reg (<MODE>mode, operands[0]);
+      }
+    else if (REG_P (operands[0])
+             && IN_RANGE (REGNO (operands[0]), FIRST_VIRTUAL_REGISTER,
+                          LAST_VIRTUAL_REGISTER))
+      {
+        // Byte-wise pushing of virtual regs might result in something like
+        //
+        //     (set (mem:QI (post_dec:HI (reg:HI 32 SP)))
+        //          (subreg:QI (plus:HI (reg:HI 28)
+        //                              (const_int 17)) 0))
+        //
+        // after elimination.  This cannot be handled by reload, cf. PR64452.
+        // Reload virtuals in one chunk.  That way it's possible to reload
+        // above situation and finally
+        //
+        //    (set (reg:HI **)
+        //         (const_int 17))
+        //    (set (reg:HI **)
+        //         (plus:HI (reg:HI **)
+        //                  (reg:HI 28)))
+        //    (set (mem:HI (post_dec:HI (reg:HI 32 SP))
+        //         (reg:HI **)))
+        emit_insn (gen_pushhi1_insn (operands[0]));
+        DONE;
+      }
 
-    for (i = GET_MODE_SIZE (<MODE>mode) - 1; i >= 0; --i)
+    for (int i = GET_MODE_SIZE (<MODE>mode) - 1; i >= 0; --i)
       {
         rtx part = simplify_gen_subreg (QImode, operands[0], <MODE>mode, i);
         if (part != const0_rtx)
index 62ae8d3c032751d23a7bba6ed450b498830c2e7c..2409cfb0fa7e788e30e0f52864b92989e57a5310 100644 (file)
@@ -1,3 +1,8 @@
+2015-02-20  Georg-Johann Lay  <avr@gjlay.de>
+
+       PR target/64452
+       * gcc.target/avr/torture/pr64452.c: New test.
+
 2015-02-19  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * gcc.dg/tree-ssa/20040204-1.c: Don't XFAIL on sh*-*-*.
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr64452.c b/gcc/testsuite/gcc.target/avr/torture/pr64452.c
new file mode 100644 (file)
index 0000000..44cb2e0
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c99" } */
+
+struct A
+{
+    char str[8];
+    void* v;
+};
+
+int varf (char* fmt, ...);
+
+void foo (struct A a, struct A b)
+{
+    varf ("%s%s", b.str, b.str);
+}
+
+long long x64;
+
+void foo2 (long long j0,
+           struct A a, struct A b, struct A c, struct A d,
+           struct A e, struct A f, struct A g, struct A h, struct A i,
+           long long j1)
+{
+    varf ("%s%s", i.str, i.str, x64, j1+j0);
+}
+
+
+void foo3 (long long j0,
+           struct A a, struct A b, struct A c, struct A d,
+           struct A e, struct A f, struct A g, struct A h, struct A i,
+           long long j1)
+{
+    varf ("%s%s", &i.str, &b.str, x64, j1+j0);
+}