https://gcc.gnu.org/g:edb025aebf799d539d9a0f56993f3cc48f9beb5b

commit r16-5634-gedb025aebf799d539d9a0f56993f3cc48f9beb5b
Author: Jeff Law <[email protected]>
Date:   Wed Nov 26 14:52:11 2025 -0700

    [RISC-V][PR rtl-optimization/122735] Avoid bogus calls to simplify_subreg
    
    Recent changes to simplify_binary_operation_1 reassociate a SUBREG 
expression
    in useful ways.  But they fail to account for the asserts at the beginning 
of
    simplify_subreg.
    
    In particular simplify_subreg asserts that the mode can not be VOID or BLK 
--
    the former being the problem here as it's used on CONST_INT nodes which may
    appear in an unsimplified REG_EQUAL note like:
    
    > (sign_extend:DI (lshiftrt:SI (const_int 19 [0x13])
    >         (subreg:QI (reg:SI 144 [ _2 ]) 0)))
    
    The extension will get canoncialized and simplified by
    expand_compound_operation resulting in a call to simplify_binary_operation
    where op0 is:
    
    > (subreg:DI (lshiftrt:SI (const_int 19 [0x13])
    >         (const_int 32 [0x20])) 0)
    
    That triggers the new code in simplify-rtx to push the subreg into an inner
    object.  In particular it'll try to push the subreg to the first operand of 
the
    LSHIFTRT.  We pass that to simplify_subreg via simplify_gen_subreg and boom!
    
    You could legitimately ask why the original note wasn't simplified further 
or
    removed.  That approach could certainly be used to fix this specific 
problem.
    But we've never had that kind of requirement on REG_EQUAL notes and I think 
it
    opens up a huge can of worms if we impose it now.   So I chose to make the
    newer simplify-rtx code more robust.
    
    Bootstrapped and regression tested on x86_64 and riscv and tested on the
    various embedded targets without regressions.  I'll wait for the pre-commit 
CI
    tester before committing.
    
            PR rtl-optimization/122735
    gcc/
            * simplify-rtx.cc (simplify_binary_operation_1): When moving a 
SUBREG
            from an outer expression to an inner operand, make sure to avoid
            trying to create invalid SUBREGs.
    
    gcc/testsuite/
    
            * gcc.dg/torture/pr122735.c: New test.

Diff:
---
 gcc/simplify-rtx.cc                     | 7 +++++++
 gcc/testsuite/gcc.dg/torture/pr122735.c | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 86baeb06ad48..3aaabdc9b055 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -4193,6 +4193,13 @@ simplify_context::simplify_binary_operation_1 (rtx_code 
code,
                 and no precision is lost.  */
              if (SUBREG_P (op0) && subreg_lowpart_p (op0)
                  && GET_CODE (XEXP (op0, 0)) == LSHIFTRT
+                 /* simplify_subreg asserts the object being accessed is not
+                    VOIDmode or BLKmode.  We may have a REG_EQUAL note which
+                    is not simplified and the source operand is a constant,
+                    and thus VOIDmode.  Guard against that.  */
+                 && GET_MODE (XEXP (XEXP (op0, 0), 0)) != VOIDmode
+                 && GET_MODE (XEXP (XEXP (op0, 0), 0)) != BLKmode
+                 && !CONST_INT_P (XEXP (XEXP (op0, 0), 0))
                  && CONST_INT_P (XEXP (XEXP (op0, 0), 1))
                  && INTVAL (XEXP (XEXP (op0, 0), 1)) >= 0
                  && INTVAL (XEXP (XEXP (op0, 0), 1)) < HOST_BITS_PER_WIDE_INT
diff --git a/gcc/testsuite/gcc.dg/torture/pr122735.c 
b/gcc/testsuite/gcc.dg/torture/pr122735.c
new file mode 100644
index 000000000000..9499ce4607b0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr122735.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+int a;
+void b() {
+  int c;
+  unsigned d = c + 19;
+  a = d >> 32 + 19 + d + 255 - 293;
+}

Reply via email to