https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128608
Bug ID: 128608
Summary: wrong code at -O2: ipa-bit-cp turns max(x, 1) of a
non-negative parameter into the constant 1
Product: gcc
Version: 16.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: ipa
Assignee: unassigned at gcc dot gnu.org
Reporter: kris.fabmoos at gmail dot com
Target Milestone: ---
Created attachment 66130
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=66130&action=edit
Testcase
Hi,
the attached test is miscompiled at -O2 and -O3 by gcc 15.2.0 and 16.2.0 on
x86_64-w64-mingw32. It has no includes, so it is already in preprocessed form.
static volatile long long sink;
__attribute__((noinline)) static long long
callee (long long lb)
{
sink = lb;
return lb;
}
__attribute__((noinline)) static long long
clamp_then_call (long long lb)
{
if (lb < 1)
lb = 1;
return callee (lb);
}
int
main (int argc, char **argv)
{
long long want = argc;
(void) argv;
if (want < 1)
want = 1;
want += 249999; /* 250000 when run without arguments */
if (clamp_then_call (1) != 1)
__builtin_abort ();
if (clamp_then_call (want) != want)
__builtin_abort (); /* aborts here */
return 0;
}
$ gcc -O2 bug.c -o bug.exe && ./bug.exe
(aborts)
$ gcc -O2 -fno-ipa-bit-cp bug.c -o bug.exe && ./bug.exe
(exit status 0)
clamp_then_call() raises its argument to at least 1 and passes it on to
callee(). main() calls it twice, with the constant 1 and with 250000. In the
-O2 build callee() receives 1 both times, so the second check aborts.
-O3 fails the same way. -O1 is fine, and so is -O2 with -fno-ipa-bit-cp or
with -fno-ipa-cp. There are no warnings with -Wall -Wextra.
What -fdump-ipa-cp-details shows (15.2.0)
The jump function for the call is an arithmetic pass-through with max_expr,
and the value range recorded next to it is correct:
callsite clamp_then_call/3 -> callee/2 :
param 0: PASS THROUGH: 0, op max_expr 1 (in type long long int)
[irange] long long int [1, +INF] MASK 0x7fffffffffffffff VALUE 0x0
The propagated bits, however, say that callee's parameter is exactly 1:
Propagated bits info for function clamp_then_call/3:
param 0: value = 0x0, mask = 0xf..f00000000ffffffff
Propagated bits info for function callee/2:
param 0: value = 0x1, mask = 0xf..f0000000000000000
So the range is right and the bits are wrong. It looks as if the bits lattice
evaluates max_expr (x, 1) for an x that is "non-negative, low bits unknown"
and concludes that the result is the constant 1. We have not read the code
closely enough to say why. One thing we noticed is that the mask has every
bit above the type's precision set, which might make the largest possible x
look negative in a signed comparison - but that is only a guess.
Other things we tried
A min version of the same test (if (x > 1000) x = 1000; with callers passing
1000 and a value in [0, 1000]) is compiled correctly by both versions.
We only have x86_64-w64-mingw32 here and nothing older than 15.2.0, so we
cannot say whether this is a regression or whether other targets are
affected. As far as we can tell nothing in the test depends on Windows.
How we found it
In a larger C program a function clamps a lower bound like this and hands it
to a checking routine, which then started from 1 on every call. Nothing
crashed. One of our test runs simply took about twenty times as long as it
should have, and that is what made us look. We now build with
-fno-ipa-bit-cp.
Compilers
gcc.exe (Rev13, Built by MSYS2 project) 15.2.0 fails
gcc.exe (Rev6, Built by MSYS2 project) 16.2.0 fails
gcc -v of the 16.2.0 build:
Target: x86_64-w64-mingw32
Configured with: ../gcc-16.2.0/configure --prefix=/ucrt64
--with-sysroot=/ucrt64 --with-build-sysroot=D:/M/msys64/ucrt64
--with-local-prefix=/local --with-native-system-header-dir=/include
--libexecdir=/ucrt64/lib --enable-bootstrap --enable-checking=release
--with-arch=nocona --with-tune=generic --enable-mingw-wildcard
--enable-languages=c,c++,ada,fortran,lto,objc,obj-c++,jit --enable-shared
--enable-static --enable-libatomic --enable-threads=posix --enable-tls
--enable-graphite --enable-fully-dynamic-string
--enable-libstdcxx-backtrace=yes --enable-libstdcxx-filesystem-ts
--enable-libstdcxx-time --disable-libstdcxx-pch --enable-libgomp
--disable-libssp --disable-multilib --disable-rpath --disable-win32-registry
--disable-nls --disable-werror --disable-symvers --with-libiconv
--with-system-zlib --with-gmp=/ucrt64 --with-mpfr=/ucrt64 --with-mpc=/ucrt64
--with-isl=/ucrt64 --with-pkgversion='Rev6, Built by MSYS2 project'
--with-bugurl=https://github.com/msys2/MINGW-packages/issues --with-gnu-as
--with-gnu-ld --with-libstdcxx-zoneinfo=yes --disable-libstdcxx-debug
--enable-lto --enable-plugin --with-boot-ldflags=-static-libstdc++
--with-stage1-ldflags=-static-libstdc++
Thread model: posix
gcc version 16.2.0 (Rev6, Built by MSYS2 project)
Thanks for taking a look.