aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2015-02-20 10:30:24 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2015-02-20 10:30:24 +0000
commit6b9861b12d076b262b86c69b1b5c30d779554384 (patch)
tree32404d84675376465de1430fa8c5ef9d914e0340 /gcc
parentdb3267c60664bcfa8d7b0683a5567b24432b5a48 (diff)
downloadgcc-6b9861b12d076b262b86c69b1b5c30d779554384.zip
gcc-6b9861b12d076b262b86c69b1b5c30d779554384.tar.gz
gcc-6b9861b12d076b262b86c69b1b5c30d779554384.tar.bz2
re PR target/64452 (ICE in avr-gcc when passing struct member to varargs function)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/avr/avr.md48
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/pr64452.c34
4 files changed, 85 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ff6df3d..8d37e35 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 5285a47..d6d930c 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -371,6 +371,13 @@
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
@@ -386,17 +393,42 @@
[(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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 62ae8d3..2409cfb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..44cb2e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr64452.c
@@ -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);
+}