aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2025-06-14 19:57:18 +0200
committerGeorg-Johann Lay <avr@gjlay.de>2025-06-14 19:59:03 +0200
commit61789b5abec3079d02ee9eaa7468015ab1f6f701 (patch)
tree27d4bc549f45d2dfb0a24d134525ab5f1090ab80
parent6923d412e61f447e423f2765b17500cc01a83c30 (diff)
downloadgcc-61789b5abec3079d02ee9eaa7468015ab1f6f701.zip
gcc-61789b5abec3079d02ee9eaa7468015ab1f6f701.tar.gz
gcc-61789b5abec3079d02ee9eaa7468015ab1f6f701.tar.bz2
AVR: Fix PR120423 / PR116389.
The problem with PR120423 and PR116389 is that reload might assign an invalid hard register to a paradoxical subreg. For example with the test case from the PR, it assigns (REG:QI 31) to the inner of (subreg:HI (QI) 0) which is valid, but the subreg will be turned into (REG:HI 31) which is invalid and triggers an ICE in postreload. The problem only occurs with the old reload pass. The patch maps the paradoxical subregs to a zero-extends which will be allocated correctly. For the 120423 testcases, the code is the same like with -mlra (which doesn't implement the fix), so the patch doesn't even introduce a performance penalty. The patch is only needed for v15: v14 is not affected, and in v16 reload will be removed. PR rtl-optimization/120423 PR rtl-optimization/116389 gcc/ * config/avr/avr.md [-mno-lra]: Add pre-reload split to transform (left shift of) a paradoxical subreg to a (left shift of) zero-extend. gcc/testsuite/ * gcc.target/avr/torture/pr120423-1.c: New test. * gcc.target/avr/torture/pr120423-2.c: New test. * gcc.target/avr/torture/pr120423-116389.c: New test.
-rw-r--r--gcc/config/avr/avr.md35
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/pr120423-1.c29
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c22
-rw-r--r--gcc/testsuite/gcc.target/avr/torture/pr120423-2.c30
4 files changed, 116 insertions, 0 deletions
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 01b8e4b..f8bbdc7 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5273,6 +5273,41 @@
;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
;; arithmetic shift left
+;; Work around PR120423: Transform left shift of a paradoxical subreg
+;; into left shift of the zero-extended entity.
+(define_split ; PR120423
+ [(set (match_operand:HISI 0 "register_operand")
+ (ashift:HISI (subreg:HISI (match_operand:QIPSI 1 "nonimmediate_operand")
+ 0)
+ (match_operand:QI 2 "const_int_operand")))]
+ "!reload_completed
+ && !avropt_lra_p
+ && <HISI:SIZE> > <QIPSI:SIZE>"
+ [(set (match_dup 4)
+ (zero_extend:HISI (match_dup 5)))
+ (set (match_dup 0)
+ (ashift:HISI (match_dup 4)
+ (match_dup 2)))]
+ {
+ operands[4] = gen_reg_rtx (<HISI:MODE>mode);
+ operands[5] = force_reg (<QIPSI:MODE>mode, operands[1]);
+ })
+
+;; Similar happens for PR116389.
+(define_split ; PR116389
+ [(set (match_operand:HISI 0 "register_operand")
+ (subreg:HISI (match_operand:QIPSI 1 "nonimmediate_operand")
+ 0))]
+ "!reload_completed
+ && !avropt_lra_p
+ && <HISI:SIZE> > <QIPSI:SIZE>"
+ [(set (match_dup 0)
+ (zero_extend:HISI (match_dup 2)))]
+ {
+ operands[2] = force_reg (<QIPSI:MODE>mode, operands[1]);
+ })
+
+
;; "ashlqi3"
;; "ashlqq3" "ashluqq3"
(define_expand "ashl<mode>3"
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr120423-1.c b/gcc/testsuite/gcc.target/avr/torture/pr120423-1.c
new file mode 100644
index 0000000..91b4bbc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr120423-1.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+
+struct data
+{
+ int a;
+ int b;
+ long c;
+};
+
+unsigned char val;
+unsigned val2;
+
+void func1 (struct data *d)
+{
+ d->a = 0;
+ d->b = 0x100 * val - 1;
+}
+
+void func2 (struct data *d)
+{
+ d->a = 0;
+ d->c = 0x10000 * val2 - 1;
+}
+
+void func3 (struct data *d)
+{
+ d->a = 0;
+ d->c = 0x1000000 * val - 1;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c b/gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c
new file mode 100644
index 0000000..928c135
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr120423-116389.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+
+struct T { int val; };
+
+void f_int (int);
+char* get_pos (void);
+struct T* get_pT (void);
+
+void func (char i)
+{
+ struct T t = * get_pT ();
+ unsigned diff = get_pos () - &i;
+
+ if (diff)
+ {
+ long val32 = t.val;
+ if (get_pos ())
+ val32 = diff;
+ if (get_pos ())
+ f_int (2 * val32);
+ }
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr120423-2.c b/gcc/testsuite/gcc.target/avr/torture/pr120423-2.c
new file mode 100644
index 0000000..56e6141
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr120423-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-ffixed-18 -ffixed-20 -ffixed-22" } */
+
+struct data
+{
+ int a;
+ int b;
+ long c;
+};
+
+unsigned char val;
+unsigned val2;
+
+void func1 (struct data *d)
+{
+ d->a = 0;
+ d->b = 0x100 * val - 1;
+}
+
+void func2 (struct data *d)
+{
+ d->a = 0;
+ d->c = 0x10000 * val2 - 1;
+}
+
+void func3 (struct data *d)
+{
+ d->a = 0;
+ d->c = 0x1000000 * val - 1;
+}