]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[RISC-V][PR rtl-optimization/122735] Avoid bogus calls to simplify_subreg
authorJeff Law <jlaw@ventanamicro.com>
Wed, 26 Nov 2025 21:52:11 +0000 (14:52 -0700)
committerJeff Law <jlaw@ventanamicro.com>
Wed, 26 Nov 2025 21:52:11 +0000 (14:52 -0700)
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.

gcc/simplify-rtx.cc
gcc/testsuite/gcc.dg/torture/pr122735.c [new file with mode: 0644]

index 86baeb06ad48819e001fffdab5208ca9336156d5..3aaabdc9b0551a02e0d1682ef22bcd9255e832ba 100644 (file)
@@ -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 (file)
index 0000000..9499ce4
--- /dev/null
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+int a;
+void b() {
+  int c;
+  unsigned d = c + 19;
+  a = d >> 32 + 19 + d + 255 - 293;
+}