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 <j...@suse.cz> 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)