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

            Bug ID: 128407
           Summary: [14/15/16/17 Regression] RTL PRE/hoist moves a
                    trapping FP truncate above a call that may exit
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: rtl-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

```c
#include <stdio.h>
#include <stdlib.h>
static unsigned overflow (void) { return __builtin_ia32_stmxcsr () & 8; }
static void at_exit (void) { printf ("overflow=%u\n", overflow ()); }
__attribute__((noipa)) void maybe_exit (int c) { if (c) exit (0); }
volatile float sinkf;
__attribute__((noipa)) int f (double d, int n, int c)
{
  int s = 0;
  for (int i = 0; i < n; i++)
    {
      maybe_exit (c);
      sinkf = (float) d;
      s++;
    }
  return s;
}
volatile double vd = 1e300;
int main (void)
{
  atexit (at_exit);
  __builtin_ia32_ldmxcsr (__builtin_ia32_stmxcsr () & ~0x3f);
  return f (vd, 10, 1);
}
```

```
$ gcc -O2 t.c && ./a.out
overflow=8
$ gcc -O2 -fno-gcse t.c && ./a.out
overflow=0
```

The double->float narrowing of 1e300 sets FE_OVERFLOW. In the source it runs
only after maybe_exit () returns, and that
call always exits, so the flag must stay clear. -O0, -O1, -Os and -O2 -fno-gcse
print overflow=0; -O2 and -O3 print
overflow=8. -fno-tree-pre -fno-code-hoisting does not help, so this is the RTL
pass. The rtl-pre dump shows
`PRE: redundant insn 17 (expression 0) in bb 4` for `(float_truncate:SF (reg
d))`, with a copy inserted on the loop
preheader edge, before the call.
-fsanitize=undefined,address,float-cast-overflow is clean, clang -O2 prints
overflow=0.

Same thing with RTL code hoisting at -Os (diamond):

```c
__attribute__((noipa)) void f (double d, int k, int c)
{
  if (k)
    { sinki = 1; sinkf = (float) d; }
  else
    { maybe_exit (c); sinkf = (float) d; }
}
/* main: f (vd, 0, 1); helpers as above, plus volatile int sinki; */
```

-Os prints overflow=8 (rtl-hoist: `PRE/HOIST: end of bb 2, insn 28, copying
expression 0`); -O2 and -Os -fno-gcse print 0.

Versions (x86_64, run on Compiler Explorer plus local builds), both testcases:
- overflow=0 (good): 7.5.0
- overflow=8 (bad): 8.5.0, 9.5.0, 10.5.0, 11.5.0, 12.5.0, 13.4.0, 14.2.0,
14.4.0, 15.3.0, 16.2.0, 16.2.1 (20261030),
  17.0 (20261030 and 20261102)

Cause: gcse.cc prune_expressions only removes may_trap_p expressions from
ANTLOC/TRANSP at blocks with an abnormal
incoming edge, and compute_hash_table_work treats a call only as a clobber of
call-clobbered registers and memory. A
register-only FP expression therefore stays transparent through a block whose
call may not return, and LCM / hoisting
places it before the call. may_trap_p itself says FLOAT_TRUNCATE traps under
the default -ftrapping-math. Other code
movers already handle this: tree PRE (BB_MAY_NOTRETURN, PR42438/PR93491; except
the FP-compare hole in PR128398), RTL loop-invariant motion (always_reached is
reset after a non-const call), and the scheduler ("Avoid moving trapping
instructions across function calls that might
not always return", last_function_call_may_noreturn in sched-deps.cc).

Possible fix (not tested): in prune_expressions, also clear TRANSP (and ANTLOC
for hoisting) of every may_trap_p
expression in blocks containing a call that may not return (as sched-deps.cc
call_may_noreturn_p decides).

Related: PR106078 (RTL PRE moves a load past a trapping division with
-fnon-call-exceptions; its draft fix only changes
memory kills), PR128229 (FP-trapping unspecs hoisted by RTL loop-invariant
motion; different pass and cause),
PR128398 (tree PRE/code hoisting moves a trapping FP compare above a call that
may not return, via vn_nary_may_trap;
same symptom, different pass: here -fno-tree-pre -fno-code-hoisting does not
help, only -fno-gcse does).

Disclaimer: This test case was found with LLM-assisted targeted testing, and
the report was written with LLM assistance.
  • [Bug rtl-optimization/128407] ... lzy20000419 at outlook dot com via Gcc-bugs

Reply via email to