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.
  • [Bug tree-optimization/128452]... lzy20000419 at outlook dot com via Gcc-bugs

Reply via email to