https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116024
Bug ID: 116024
Summary: [14/15 Regression] unnecessary integer comparison(s)
for a simple loop
Product: gcc
Version: 14.1.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: ipa
Assignee: unassigned at gcc dot gnu.org
Reporter: artemiy at synopsys dot com
CC: jh at suse dot cz
Target Milestone: ---
Target: riscv32-unknown-elf
gcc 14 and later emits unnecessary instructions when compiling the i() function
in the following code:
$ cat test.i
# 0 "test.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "test.c"
typedef enum { a, b } c;
extern char d, e;
c f()
{
if (d)
return a;
d = e;
return b;
}
void i()
{
int l = 2;
while (l <= 2)
if (f() == a)
l++;
}
$ riscv32-unknown-elf-gcc test.i -S -O3 -fno-inline -Wall -Wextra
$ cat test.s
[snip]
i:
addi sp,sp,-16
sw s0,8(sp)
sw s1,4(sp)
sw ra,12(sp)
li s1,3
li s0,2
.L6:
call f
sub a0,s1,a0
beq a0,s0,.L6
[snip]
gcc 13.2.0 doesn’t load any immediates and just emits a branch-if-not-zero:
[snip]
i:
addi sp,sp,-16
sw ra,12(sp)
.L6:
call f
bne a0,zero,.L6
[snip]
I have bisected the introduction of this behavior down to:
commit 53ba8d669550d3a1f809048428b97ca607f95cf5
Author: Jan Hubicka <[email protected]>
Date: Mon Nov 20 19:35:53 2023 +0100
inter-procedural value range propagation
I can't be too sure, but I think what ends up happening is that the ipa-cp pass
propagates the range of return values of f() ({0,1}), then later on phiopt2
uses this to expand the PHI node to something like 3 - f() == 2:
<bb 3> [local count: 955630224]:
# DEBUG BEGIN_STMT
_1 = f ();
_6 = (int) _1;
_8 = 3 - _6;
<bb 4> [local count: 1073741824]:
# l_2 = PHI <_8(3), 2(2)>
# DEBUG l => l_2
# DEBUG BEGIN_STMT
if (l_2 == 2)
goto <bb 3>; [89.00%]
else
goto <bb 5>; [11.00%]
And the aforementioned expression never gets simplified back to f() != 0,
resulting in more complicated assembly code. Indeed, specifying -fno-ipa-vrp
(or -fno-ssa-phiopt) works as a temporary workaround.
godbolt for convenience: https://godbolt.org/z/xr1oTrW51
gcc -v output:
$ riscv32-unknown-elf-gcc -v
Using built-in specs.
COLLECT_GCC=riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/home/art/work/install/riscv-gnu-toolchain/libexec/gcc/riscv32-unknown-elf/15.0.0/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /home/art/work/src/gcc/configure --target=riscv32-unknown-elf
--prefix=/home/art/work/install/riscv-gnu-toolchain --disable-shared
--disable-threads --enable-languages=c,c++ --with-pkgversion=g80c37335baf
--with-system-zlib --enable-tls --with-newlib
--with-sysroot=/home/art/work/install/riscv-gnu-toolchain/riscv32-unknown-elf
--with-native-system-header-dir=/include --disable-libmudflap --disable-libssp
--disable-libquadmath --disable-libgomp --disable-nls
--disable-tm-clone-registry --src=/home/art/work/src/gcc --enable-multilib
--with-abi=ilp32 --with-arch=rv32gc --with-tune=rocket --with-isa-spec=20191213
'CFLAGS_FOR_TARGET=-Os ' 'CXXFLAGS_FOR_TARGET=-Os '
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 15.0.0 20240721 (experimental) (g80c37335baf)