https://gcc.gnu.org/g:61789b5abec3079d02ee9eaa7468015ab1f6f701

commit r15-9837-g61789b5abec3079d02ee9eaa7468015ab1f6f701
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Sat Jun 14 19:57:18 2025 +0200

    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.

Diff:
---
 gcc/config/avr/avr.md                              | 35 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/avr/torture/pr120423-1.c  | 29 ++++++++++++++++++
 .../gcc.target/avr/torture/pr120423-116389.c       | 22 ++++++++++++++
 gcc/testsuite/gcc.target/avr/torture/pr120423-2.c  | 30 +++++++++++++++++++
 4 files changed, 116 insertions(+)

diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 01b8e4bce4cf..f8bbdc766085 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 000000000000..91b4bbc812c8
--- /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 000000000000..928c1358c3c3
--- /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 000000000000..56e61415afb9
--- /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;
+}

Reply via email to