https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128452
Bug ID: 128452
Summary: [14/15/16/17 Regression] wrong code with
-fassociative-math: reassoc decrement_power turns pow
(x, -2^63) into pow (x, 2^63-1)
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: lzy20000419 at outlook dot com
Target Milestone: ---
Host: x86_64-pc-linux-gnu
Target: x86_64-pc-linux-gnu
Build: x86_64-pc-linux-gnu
Split out from PR128006 (issue 1 of comment 4) at the maintainer's request.
r17-5395 makes sure the exponent is an integer, but decrement_power still wraps
for the integer-minimum exponent. The testcase is UB-free (x = -1 keeps every
intermediate at +-1):
```c
#include <math.h>
__attribute__((noipa)) double f (double x, double y, double z)
{
return (x * y) * pow (x, -9223372036854775808.0) + z * x;
}
int main (void)
{
if (f (-1.0, 1.0, 0.0) != -1.0) __builtin_abort ();
if (f (-1.0, 1.0, 1.0) != -2.0) __builtin_abort ();
return 0;
}
```
```
$ gcc -O2 -fassociative-math -fno-signed-zeros -fno-trapping-math t.c -lm &&
./a.out
Aborted
$ gcc -O2 -fassociative-math -fno-signed-zeros -fno-trapping-math
-fno-tree-reassoc t.c -lm && ./a.out # ok
```
The reassoc1 dump has `_12 = pow (x_5(D), 9.223372036854775807e+18);`, i.e. the
exponent went from -2^63 to +2^63-1 Since -2^63 is even and 2^63-1 is odd, with
x = -1 the sign of the result flips.
Tested on trunk 17.0.0 20261105 (2175b27369e5), 16.2.1 and 14.2.0: all abort.
On Compiler Explorer it aborts from 8.1.0 through trunk (8.5.0, 9.5.0, 10.5.0,
11.4.0, 12.4.0, 13.4.0, 14.2.0, 15.3.0, 16.2.0) and works with 7.5.0 and 6.5.0.
Godbolt (execution on trunk, 16.2, 14.2 and 7.5; 7.5 works):
https://godbolt.org/z/bE8c565jT
In decrement_power (tree-ssa-reassoc.cc:1231 on trunk), `power =
real_to_integer (&c) - 1;` (:1242) overflows for c = -2^63 and wraps to
HOST_WIDE_INT_MAX. The powi branch (:1249, TREE_INT_CST_LOW (arg1) - 1) has the
same pattern.
A possible one-line fix (not tested) is to have stmt_is_power_of_op reject a
pow/powi whose exponent minus one is not representable (e.g. require the
exponent to be greater than HOST_WIDE_INT_MIN, and greater than the minimum of
the powi argument type).
Disclaimer: This test case was found with LLM-assisted targeted testing, and
the report was written with LLM assistance.