https://gcc.gnu.org/g:ee8e6784876aa050d2e01f54d1da4acf758b635a

commit r15-5607-gee8e6784876aa050d2e01f54d1da4acf758b635a
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Sat Nov 23 12:51:32 2024 +0100

    AVR: target/117744 - Fix asm for partial clobber of address reg,
    
    gcc/
            PR target/117744
            * config/avr/avr.cc (out_movqi_r_mr): Fix code when a load
            only partially clobbers an address register due to
            changing the address register temporally to accomodate for
            faked addressing modes.

Diff:
---
 gcc/config/avr/avr.cc | 64 ++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 19 deletions(-)

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 64d7795f37cc..940ac3f0279e 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -4055,11 +4055,11 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx 
op[], int *plen)
       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 ("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);
+       avr_asm_len ("mov %0,__tmp_reg__", &base2, plen, 1);
     }
 
   return "";
@@ -4086,40 +4086,66 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen)
     {
       /* memory access by reg+disp */
 
-      int disp = INTVAL (XEXP (x, 1));
-
       if (AVR_TINY)
        return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen);
 
+      if (plen)
+       *plen = 0;
+
+      int disp = INTVAL (XEXP (x, 1));
+      rtx base = XEXP (x, 0);
+      rtx base2 = all_regs_rtx[1 ^ REGNO (dest)];
+      bool partial_clobber = (reg_overlap_mentioned_p (dest, base)
+                             && ! reg_unused_after (insn, base2));
+
       if (disp - GET_MODE_SIZE (GET_MODE (src)) >= 63)
        {
+         // PR117744: The base register overlaps dest and is
+         // only partially clobbered.
+         if (partial_clobber)
+           avr_asm_len ("mov __tmp_reg__,%0", &base2, plen, 1);
+
          if (REGNO (XEXP (x, 0)) != REG_Y)
            fatal_insn ("incorrect insn:",insn);
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
-           return avr_asm_len ("adiw r28,%o1-63" CR_TAB
-                               "ldd %0,Y+63"     CR_TAB
-                               "sbiw r28,%o1-63", op, plen, -3);
+           avr_asm_len ("adiw r28,%o1-63" CR_TAB
+                        "ldd %0,Y+63"     CR_TAB
+                        "sbiw r28,%o1-63", op, plen, 3);
+         else
+           avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB
+                        "sbci r29,hi8(-%o1)" CR_TAB
+                        "ld %0,Y"            CR_TAB
+                        "subi r28,lo8(%o1)"  CR_TAB
+                        "sbci r29,hi8(%o1)", op, plen, 5);
 
-         return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB
-                             "sbci r29,hi8(-%o1)" CR_TAB
-                             "ld %0,Y"            CR_TAB
-                             "subi r28,lo8(%o1)"  CR_TAB
-                             "sbci r29,hi8(%o1)", op, plen, -5);
+         if (partial_clobber)
+           avr_asm_len ("mov __tmp_reg__,%0", &base2, plen, 1);
+
+         return "";
        }
       else if (REGNO (XEXP (x, 0)) == REG_X)
        {
          /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
             it but I have this situation with extremal optimizing options.  */
 
-         avr_asm_len ("adiw r26,%o1" CR_TAB
-                      "ld %0,X", op, plen, -2);
+         // PR117744: The base register overlaps dest and is
+         // only partially clobbered.
+         bool clobber_r26 = (partial_clobber
+                             && REGNO (base) == (REGNO (base) & ~1));
+         if (partial_clobber
+             && ! clobber_r26)
+           avr_asm_len ("mov __tmp_reg__,%0", &base2, plen, 1);
 
-         if (!reg_overlap_mentioned_p (dest, XEXP (x, 0))
-             && !reg_unused_after (insn, XEXP (x, 0)))
-           {
-             avr_asm_len ("sbiw r26,%o1", op, plen, 1);
-           }
+         avr_asm_len ("adiw r26,%o1" CR_TAB
+                      "ld %0,X", op, plen, 2);
+
+         if (clobber_r26)
+           avr_asm_len ("subi r26,lo8(%o1)", op, plen, 1);
+         else if (partial_clobber)
+           avr_asm_len ("mov %0,__tmp_reg__", &base2, plen, 1);
+         else if (! reg_unused_after (insn, base))
+           avr_asm_len ("sbiw r26,%o1", op, plen, 1);
 
          return "";
        }

Reply via email to