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.

Jeff


        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 --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