https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128229

            Bug ID: 128229
           Summary: [9/10/11/12/13/14/15/16/17 Regression] x86:
                    FP-trapping unspecs (cvtsd2si / lrint, minpd) hoisted
                    out of a guarded loop by RTL loop-invariant motion;
                    default_unspec_may_trap_p ignores operand modes and
                    vector-float result modes
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: lzy20000419 at outlook dot com
  Target Milestone: ---

```c
#include <fenv.h>
#include <stdio.h>
#include <immintrin.h>
volatile int sink;
int a[16];   /* all zero: the guarded statement never runs */
__attribute__((noipa)) void f (double x, int n)
{
  for (int i = 0; i < n; i++)
    if (a[i])
      sink = _mm_cvtsd_si32 (_mm_set_sd (x));
}
int main (void)
{
  feclearexcept (FE_ALL_EXCEPT);
  f (__builtin_nan (""), 16);
  printf ("%d\n", fetestexcept (FE_INVALID) != 0);   /* expect 0 */
}
```

`a[]` is all zero, so the conversion never runs and no FP exception may be
raised. Expected output is 0.

- `gcc -O1` / `-O2` / `-Os t.c -lm` → prints 1. `cvtsd2sil %xmm0, %ecx` is
placed before the loop, behind only the `n > 0` test.
- `-O0`, `-O2 -fno-move-loop-invariants`, clang -O2 → 0. With `feenableexcept
(FE_INVALID)` the -O2 binary gets SIGFPE.
- n = 0 → 0 (the loop is not entered), n = 1 → 1.
- trunk: https://godbolt.org/z/54MzasYxE (executors: -O2 → 1, -O2
-fno-move-loop-invariants → 0, -O0 → 0)

Same thing with a vector-float unspec (`_mm_min_pd` → `UNSPEC_IEEE_MIN`, V2DF
result; `minpd` with a NaN operand raises FE_INVALID):

```c
volatile double sink;
int a[16];
__attribute__((noipa)) void f (__m128d x, __m128d y, int n)
{
  for (int i = 0; i < n; i++)
    if (a[i])
      sink = _mm_cvtsd_f64 (_mm_min_pd (x, y));
}
/* main: f (_mm_set1_pd (NaN), _mm_set1_pd (1.0), 16); expect FE_INVALID clear
*/
```

-O1/-O2/-Os → 1, -O0 / -fno-move-loop-invariants / clang → 0. trunk:
https://godbolt.org/z/nrPesnefW

And without intrinsics: `sink = __builtin_lrint (x);` (volatile long sink) at
`-O2 -fno-math-errno` → 1 (`-O0` and `-fno-move-loop-invariants` give 0).

Versions (-O2): the cvtsd2si case fails on 9.1 through trunk and works on 8.5
and 7.5. The minpd case fails on 6.5 through trunk and works on 6.1 and 5.4.
The lrint case fails on 8.1 through trunk and works on 7.5.

Reply via email to