https://gcc.gnu.org/g:55744507abc5240fe1a59a6251f815a0d6217fe8

commit r14-10373-g55744507abc5240fe1a59a6251f815a0d6217fe8
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Wed Jul 3 10:29:18 2024 +0200

    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.
    
    (cherry picked from commit e9fb6efa1cf542353fd44ddcbb5136344c463fd0)

Diff:
---
 gcc/config/avr/avr.cc                          | 27 +++++++++++++++++++++-----
 gcc/testsuite/gcc.target/avr/torture/pr98762.c | 19 ++++++++++++++++++
 2 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index e516c19322c..b41592ff1a3 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 00000000000..c3ba7da69a8
--- /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;
+}

Reply via email to