On Mon, Dec 19, 2022 at 09:49:36AM +0100, Richard Biener wrote:
> On Mon, Dec 19, 2022 at 9:12 AM Kewen.Lin <li...@linux.ibm.com> wrote:
> > In function fold_convert_const_real_from_real, when the modes of
> > two types involved in fp conversion are the same, we can simply
> > take it as copy, rebuild with the exactly same TREE_REAL_CST and
> > the target type.  It is more efficient and helps to avoid possible
> > unexpected signalling bit clearing in [1].
> >
> > Bootstrapped and regtested on x86_64-redhat-linux, aarch64-linux-gnu
> > and powerpc64{,le}-linux-gnu.
> >
> > Is it ok for trunk?
> 
> But shouldn't
> 
> double x = (double) __builtin_nans("sNAN");
> 
> result in a quiet NaN?

I think it doesn't already, fold_convert_const starts with
  tree arg_type = TREE_TYPE (arg1);
  if (arg_type == type)
    return arg1;
and so if it is a conversion to the same type, fold_convert_const_real_from_real
won't be called at all.
It is just cast to a different type with same mode (say typedef double doublet)
that triggers it right now.
Try:

double
foo (void)
{
  return __builtin_nans ("");
}

double
bar (void)
{
  return (double) __builtin_nans ("");
}

typedef double doublet;

doublet
baz (void)
{
  return __builtin_nans ("");
}

doublet
qux (void)
{
  return (doublet) __builtin_nans ("");
}

float
corge (void)
{
  return (float) __builtin_nans ("");
}

GCC right now returns a sNaN in foo and bar and qNaN in baz, qux and corge,
clang and ICC (tried 19.0.1 on godbolt) return sNaN in foo, bar, baz, qux
and qNaN in corge.

The last case is required by C:
convertFormat - different formats       cast and implicit conversions   
6.3.1.5, 6.5.4
convertFormat - same format             canonicalize                    
7.12.11.7, F.10.8.7
As for the rest, C n3047.pdf has:
Whether C assignment (6.5.16) (and conversion as if by assignment) to the same 
format is an
IEC 60559 convertFormat or copy operation439) is implementation-defined, even 
if <fenv.h> defines
the macro FE_SNANS_ALWAYS_SIGNAL (F.2.1). If the return expression of a return 
statement is
evaluated to the floating-point format of the return type, it is 
implementation-defined whether a
convertFormat operation is applied to the result of the return expression.

439) Where the source and destination formats are the same, convertFormat 
operations differ from copy operations in
that convertFormat operations raise the "invalid" floating-point exception on 
signaling NaN inputs and do not propagate
non-canonical encodings.

I think the posted patch is good for consistency, treating conversion to the
same format sometimes as convertFormat and sometimes as copy is maybe valid
but confusing, especially when on:

double
foo (double x)
{
  return x;
}

double
bar (double x)
{
  return (double) x;
}

typedef double doublet;

doublet
baz (double x)
{
  return x;
}

doublet
qux (double x)
{
  return (doublet) x;
}

float
corge (double x)
{
  return (float) x;
}
we actually use copy operations in all of foo, bar, baz and qux.

        Jakub

Reply via email to