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