https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127876
Bug ID: 127876
Summary: Wrong code at -O3: conditional reduction to -0.0
returns +0.0 (CONST_COND_REDUCTION uses MAX_EXPR)
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: kyuwoncho18 at gmail dot com
Target Milestone: ---
godbolt: https://godbolt.org/z/drczvec53
```c
#include <stdio.h>
#include <string.h>
__attribute__((noinline))
double f (double *a, int n)
{
double r = 0.0;
for (int i = 0; i < n; i++)
if (a[i] > 100.0)
r = -0.0;
return r;
}
int main (void)
{
double a[32];
for (int i = 0; i < 32; i++)
a[i] = 1.0;
a[7] = 200.0;
double r = f (a, 32);
unsigned long long bits;
memcpy (&bits, &r, sizeof bits);
printf ("r=%g bits=%016llx\n", r, bits);
return 0;
}
```
```console
$ gcc -O3 t.c && ./a.out
r=0 bits=0000000000000000
$ gcc -O3 -fno-tree-vectorize t.c && ./a.out
r=-0 bits=8000000000000000
```
Expected `-0` (bits `8000000000000000`): `a[7] > 100.0`, so `r` is set to
`-0.0`, and signed zeros are honored by default (`-O3 -fsigned-zeros` still
prints `0`). Clang prints `-0`.
The loop is vectorized as a `CONST_COND_REDUCTION`. `vectorizable_reduction`
picks `MAX_EXPR` because `fold_binary (LE_EXPR, 0.0, -0.0)` is true, but MAX
cannot tell `-0.0` from the initial `+0.0`. Nothing on this path checks
`HONOR_SIGNED_ZEROS`.
Fails with GCC 9.1 through trunk (17.0.0 20261012). The surviving sign depends
on which lane holds the `-0.0`: with `a[6] = 200.0` instead, trunk prints `-0`
but GCC 8.5 prints `0`.
Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.