]> git.ipfire.org Git - thirdparty/gcc.git/commit
combine: Fix up make_extraction [PR118638]
authorJakub Jelinek <jakub@redhat.com>
Tue, 28 Jan 2025 09:14:05 +0000 (10:14 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 28 Jan 2025 09:14:05 +0000 (10:14 +0100)
commitb529a417249335724d1f74bcf3167f6f9a623823
tree91665da04b3b09d8969fe1146b0d07f031c8e485
parent115255589cba449f1b10464f47646bda69c768fb
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  <jakub@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.
gcc/combine.cc
gcc/testsuite/gcc.c-torture/execute/pr118638.c [new file with mode: 0644]