aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2025-02-14 18:53:29 +0100
committerGeorg-Johann Lay <avr@gjlay.de>2025-02-14 22:34:44 +0100
commit1dc4e220ca2272d668ddb3041ccd9e69b968e532 (patch)
tree379d5ce8d25515b3515eab73019a31416393ecd8 /gcc
parent2b9bdb2d286e6872f4195ba2e710130cf6b2805d (diff)
downloadgcc-1dc4e220ca2272d668ddb3041ccd9e69b968e532.zip
gcc-1dc4e220ca2272d668ddb3041ccd9e69b968e532.tar.gz
gcc-1dc4e220ca2272d668ddb3041ccd9e69b968e532.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/avr/avr.cc20
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/pr118878.c78
2 files changed, 91 insertions, 7 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index bb00e33..e358a2e 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 0000000..d2d8a22
--- /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