https://gcc.gnu.org/g:1dc4e220ca2272d668ddb3041ccd9e69b968e532

commit r15-7544-g1dc4e220ca2272d668ddb3041ccd9e69b968e532
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Fri Feb 14 18:53:29 2025 +0100

    AVR: target/118878 - Don't ICE on result from paradoxical reg's alloc.
    
    After register allocation, paradoxical subregs may become something
    like  r20:SI += r22:SI  which doesn't make much sense as assembly code.
    Hence avr_out_plus_1() used to ICE on such code.  However, paradoxical
    subregs appear to be a common optimization device (instead of proper
    mode demotion).
    
            PR target/118878
    gcc/
            * config/avr/avr.cc (avr_out_plus_1): Don't ICE on result of
            paradoxical reg's register allocation.
    gcc/testsuite/
            * gcc.target/avr/torture/pr118878.c: New test.

Diff:
---
 gcc/config/avr/avr.cc                           | 20 ++++---
 gcc/testsuite/gcc.target/avr/torture/pr118878.c | 78 +++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 7 deletions(-)

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index bb00e3347206..e358a2e8b8da 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -8782,6 +8782,16 @@ avr_out_plus_1 (rtx insn, rtx *xop, int *plen, rtx_code 
code,
 
   if (REG_P (xop[2]))
     {
+      if (REGNO (xop[0]) != REGNO (xop[2])
+         && reg_overlap_mentioned_p (xop[0], xop[2]))
+       {
+         /* PR118878: Paradoxical SUBREGs may result in overlapping
+            registers.  The assumption is that the overlapping part
+            is unused garbage.  */
+         gcc_assert (n_bytes <= 4);
+         n_bytes = std::abs ((int) REGNO (xop[0]) - (int) REGNO (xop[2]));
+       }
+
       for (int i = 0; i < n_bytes; i++)
        {
          /* We operate byte-wise on the destination.  */
@@ -8796,13 +8806,9 @@ avr_out_plus_1 (rtx insn, rtx *xop, int *plen, rtx_code 
code,
                         op, plen, 1);
        }
 
-      if (reg_overlap_mentioned_p (xop[0], xop[2]))
-       {
-         gcc_assert (REGNO (xop[0]) == REGNO (xop[2]));
-
-         if (MINUS == code)
-           return;
-       }
+      if (MINUS == code
+         && REGNO (xop[0]) == REGNO (xop[2]))
+       return;
 
       goto saturate;
     }
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr118878.c 
b/gcc/testsuite/gcc.target/avr/torture/pr118878.c
new file mode 100644
index 000000000000..d2d8a22fbda7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr118878.c
@@ -0,0 +1,78 @@
+/* { dg-do run { target { ! avr_tiny } } } */
+/* { dg-additional-options { -std=c99 } } */
+
+#ifdef __AVR_HAVE_LPMX__
+
+/* From include <avr/pgmspace.h> */
+
+typedef __UINT8_TYPE__ uint8_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef uint32_t uint_farptr_t;
+
+#define pgm_read_dword_far(__addr) __ELPM_dword (__addr)
+
+#define __ELPM_dword(addr)                        \
+  (__extension__({                                \
+      uint_farptr_t __addr32 = (addr);            \
+      uint32_t __result;                          \
+      __ELPM__4 (__result, __addr32, uint32_t);   \
+      __result; }))
+
+/* Has no ELPM: Fallback to LPM. */
+#define __ELPM__4(r,a,T) const T *__a = (const T*)(uint16_t) a; __LPM__4(r,__a)
+
+#define __LPM__4(res,addr)              \
+  __asm volatile ("lpm %A0,%a1+" "\n\t" \
+                  "lpm %B0,%a1+" "\n\t" \
+                  "lpm %C0,%a1+" "\n\t" \
+                  "lpm %D0,%a1+" : "=r" (res), "+z" (addr))
+
+#define PROGMEM __attribute__((__progmem__))
+
+#define pgm_get_far_address(var)              \
+  (__extension__({ uint_farptr_t __tmp;       \
+      __asm__ ("ldi    %A0, lo8(%1)" "\n\t"   \
+               "ldi    %B0, hi8(%1)" "\n\t"   \
+               "ldi    %C0, hh8(%1)" "\n\t"   \
+               "clr    %D0" : "=d" (__tmp) : "i" (&(var)) ); __tmp; }))
+
+/*********************************************/
+
+#define VAL 0x01050711
+
+PROGMEM
+const uint32_t data[] = { VAL, 2 * VAL, 7 * VAL };
+
+uint32_t get_val (uint8_t i)
+{
+  uint32_t v = VAL;
+  if (i == 1) v *= 2;
+  if (i == 2) v *= 7;
+  return v;
+}
+
+__attribute__((noinline,noclone))
+void test (uint8_t i)
+{
+  if (pgm_read_dword_far (pgm_get_far_address (data[0])) != get_val (0))
+    __builtin_exit (__LINE__);
+
+  uint_farptr_t pf = pgm_get_far_address (data[0]) + i * sizeof (uint32_t);
+  if (pgm_read_dword_far (pf) != get_val (i))
+    __builtin_exit (__LINE__);
+}
+
+int main (void)
+{
+  test (1);
+  test (2);
+  return 0;
+}
+
+#else
+int main (void)
+{
+  return 0;
+}
+#endif

Reply via email to