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

commit r15-7246-gb529a417249335724d1f74bcf3167f6f9a623823
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Jan 28 10:14:05 2025 +0100

    combine: Fix up make_extraction [PR118638]
    
    The following testcase is miscompiled at -Os on x86_64-linux.
    The problem is during make_compound_operation of
    (ashiftrt:SI (ashift:SI (mult:SI (reg:SI 107 [ a_5 ])
                (const_int 3 [0x3]))
            (const_int 31 [0x1f]))
        (const_int 31 [0x1f]))
    where it incorrectly returns
    (mult:SI (sign_extract:SI (reg:SI 107 [ a_5 ])
            (const_int 2 [0x2])
            (const_int 0 [0]))
        (const_int 3 [0x3]))
    which isn't obviously true, the former returns either 0 or -1 depending
    on the least significant bit of the multiplication,
    the latter returns either 0 or -3 depending on the second least significant
    bit of the multiplication argument.
    
    The bug has been introduced in PR96998 r11-4563, which added handling of x
    * (2^N) similar to x << N.  In the above case, pos is 0 and len is 1,
    sign extracting a single least significant bit of the multiplication.
    As 3 is not a power of 2, shift_amt is -1.
    But IN_RANGE (-1, 1, 1 - 1) is still true, because the basic requirement of
    IN_RANGE that LOWER is not greater than UPPER is violated.
    The intention of using 1 as LOWER is to avoid matching multiplication by 1,
    that really shouldn't appear in the IL.  But to avoid violating IN_RANGE
    requirement, we need to verify that len is at least 2.
    
    I've added this len > 1 check to the inner if rather than outer because I
    think for GCC 16 we should add a further optimization.
    In the particular case of 1 least significant bit sign extraction from
    multiplication by 3, we could actually say it is equivalent to
    (sign_extract:SI (reg:SI 107 [ a_5 ])
            (const_int 1 [0x2])
            (const_int 0 [0]))
    That is because 3 is an odd number and multiplication by 2 will yield the
    least significant bit 0 (we are sign extracting just one) and so the
    multiplication doesn't change anything on the outcome.
    More generally, even for larger len, multiplication by C which is
    (1 << X) + 1 where X is >= len should be optimizable just to extraction
    of the multiplicand's least significant len bits.
    
    2025-01-28  Jakub Jelinek  <ja...@redhat.com>
    
            PR rtl-optimization/118638
            * combine.cc (make_extraction): Only optimize (mult x 2^n) if len is
            larger than 1.
    
            * gcc.c-torture/execute/pr118638.c: New test.

Diff:
---
 gcc/combine.cc                                 |  2 +-
 gcc/testsuite/gcc.c-torture/execute/pr118638.c | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/gcc/combine.cc b/gcc/combine.cc
index b0159b23d869..90828108ba4c 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -7629,7 +7629,7 @@ make_extraction (machine_mode mode, rtx inner, 
HOST_WIDE_INT pos,
         least significant (LEN - C) bits of X, giving an rtx
         whose mode is MODE, then multiply it by 2^C.  */
       const HOST_WIDE_INT shift_amt = exact_log2 (INTVAL (XEXP (inner, 1)));
-      if (IN_RANGE (shift_amt, 1, len - 1))
+      if (len > 1 && IN_RANGE (shift_amt, 1, len - 1))
        {
          new_rtx = make_extraction (mode, XEXP (inner, 0),
                                     0, 0, len - shift_amt,
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr118638.c 
b/gcc/testsuite/gcc.c-torture/execute/pr118638.c
new file mode 100644
index 000000000000..5c0dbca5c09a
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr118638.c
@@ -0,0 +1,20 @@
+/* PR rtl-optimization/118638 */
+
+__attribute__((noipa)) int
+foo (int x)
+{
+  int a = x != -3, b, c;
+  a *= 3;
+  b = 2 * x - 9;
+  a = a + b;
+  a = ~a;
+  c = a & 1;
+  return -c;
+}
+
+int
+main ()
+{
+  if (foo (0) != -1)
+    __builtin_abort ();
+}

Reply via email to