aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2024-07-03 10:29:18 +0200
committerGeorg-Johann Lay <avr@gjlay.de>2024-07-03 10:33:15 +0200
commite9fb6efa1cf542353fd44ddcbb5136344c463fd0 (patch)
tree9e7ab06db42291d742736a781caab376d06e9a4c
parent735edbf1e2479fa2323a2b4a9714fae1a0925f74 (diff)
downloadgcc-e9fb6efa1cf542353fd44ddcbb5136344c463fd0.zip
gcc-e9fb6efa1cf542353fd44ddcbb5136344c463fd0.tar.gz
gcc-e9fb6efa1cf542353fd44ddcbb5136344c463fd0.tar.bz2
AVR: target/98762 - Handle partial clobber in movqi output.
PR target/98762 gcc/ * config/avr/avr.cc (avr_out_movqi_r_mr_reg_disp_tiny): Properly restore the base register when it is partially clobbered. gcc/testsuite/ * gcc.target/avr/torture/pr98762.c: New test.
-rw-r--r--gcc/config/avr/avr.cc27
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/pr98762.c19
2 files changed, 41 insertions, 5 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index a110af6..f048bf5 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -4838,13 +4838,30 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen)
rtx dest = op[0];
rtx src = op[1];
rtx x = XEXP (src, 0);
+ rtx base = XEXP (x, 0);
- avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
- "ld %0,%b1" , op, plen, -3);
+ if (plen)
+ *plen = 0;
- if (!reg_overlap_mentioned_p (dest, XEXP (x, 0))
- && !reg_unused_after (insn, XEXP (x, 0)))
- avr_asm_len (TINY_SBIW (%I1, %J1, %o1), op, plen, 2);
+ if (!reg_overlap_mentioned_p (dest, base))
+ {
+ avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
+ "ld %0,%b1", op, plen, 3);
+ if (!reg_unused_after (insn, base))
+ avr_asm_len (TINY_SBIW (%I1, %J1, %o1), op, plen, 2);
+ }
+ else
+ {
+ // PR98762: The base register overlaps dest and is only partly clobbered.
+ rtx base2 = all_regs_rtx[1 ^ REGNO (dest)];
+
+ if (!reg_unused_after (insn, base2))
+ avr_asm_len ("mov __tmp_reg__,%0" , &base2, plen, 1);
+ avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB
+ "ld %0,%b1", op, plen, 3);
+ if (!reg_unused_after (insn, base2))
+ avr_asm_len ("mov %0,__tmp_reg__" , &base2, plen, 1);
+ }
return "";
}
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr98762.c b/gcc/testsuite/gcc.target/avr/torture/pr98762.c
new file mode 100644
index 0000000..c3ba7da
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr98762.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-additional-options "-std=c99" } */
+
+long long acc = 0x1122334455667788;
+
+__attribute__((noinline,noclone))
+void addhi (short a)
+{
+ acc += (long long) a << 32;
+}
+
+int main (void)
+{
+ addhi (0x0304);
+ if (acc != 0x1122364855667788)
+ __builtin_abort();
+
+ return 0;
+}