This patch fixes an ICE on trunk, so I don't plan to backport.
Ok for trunk?
Johann
--
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 --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index bb00e334720..e358a2e8b8d 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 00000000000..d2d8a22fbda
--- /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