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;
}

Reply via email to