https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127872
Bug ID: 127872
Summary: storing a signaling NaN constant uses flds/fstps and
quietens it with -mfpmath=387
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: rguenth at gcc dot gnu.org
Target Milestone: ---
Target: i?86-*-*
The following fails at -O0, -O2, RTL expansion emits
(set (reg:SF) (mem:SF .LC0))
followed by
(set (mem:SF ..) (reg:SF))
for each store. With one store, fwprop/combine at -O1+ turn this into
movl $0x7fa00000, (%eax)
at -O0 it stays flds .LC0; fstps (%eax).
With several stores of the same constant, cse1 shares the pseudo and IRA
allocates it to an x87 register: flds .LC0; fsts (%eax); fsts 4(%eax);
The pseudo is only ever moved, so a general register (or immediate stores)
would preserve the bits. Possible fixes: expand constant SF/DF stores as
integer immediate stores when `!mode_can_transfer_bits`, or make the movsf/df
costs prefer GPRs for pseudos that only feed stores.
/* Storing a signaling NaN constant to memory quietens it with x87 math.
{ dg-do run }
{ dg-options "-O2 -mfpmath=387 -mno-sse -fsignaling-nans" }
{ dg-require-effective-target ia32 } */
__attribute__((noipa)) void
store1_f (float *p)
{
*p = __builtin_nansf ("");
}
/* With -O1 and higher the single store above is emitted as an immediate
move, but once the constant has several uses CSE shares the pseudo and
IRA assigns it to an x87 register: flds .LC0; fsts; fsts; ... */
__attribute__((noipa)) void
store4_f (float *p)
{
float x = __builtin_nansf ("");
p[0] = x;
p[1] = x;
p[2] = x;
p[3] = x;
}
__attribute__((noipa)) void
store2_d (double *p)
{
double x = __builtin_nans ("");
p[0] = x;
p[1] = x;
}
int
main ()
{
union { float f[4]; unsigned int i[4]; } uf;
union { double d[2]; unsigned long long l[2]; } ud;
store1_f (uf.f);
if (uf.i[0] != 0x7fa00000u)
__builtin_abort ();
store4_f (uf.f);
for (int i = 0; i < 4; i++)
if (uf.i[i] != 0x7fa00000u)
__builtin_abort ();
store2_d (ud.d);
for (int i = 0; i < 2; i++)
if (ud.l[i] != 0x7ff4000000000000ull)
__builtin_abort ();
return 0;
}