https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99497
--- Comment #1 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Simplified:
#include <x86intrin.h>
void
print128 (__m128 var)
{
float val[4];
__builtin_memcpy (val, &var, sizeof(val));
__builtin_printf ("%f %f %f %f \n", val[0], val[1], val[2], val[3]);
}
int
main ()
{
__m128 a = _mm_set_ss (__builtin_nanf (""));
__m128 b = _mm_set_ss (2.0f);
__m128 c = _mm_max_ss (a, b);
__m128 d = _mm_max_ss (b, a);
print128 (c);
print128 (d);
return 0;
}
The RTL SMAX etc. ops are defined as:
/* Minimum and maximum values of two operands. We need both signed and
unsigned forms. (We cannot use MIN for SMIN because it conflicts
with a macro of the same name.) The signed variants should be used
with floating point. Further, if both operands are zeros, or if either
operand is NaN, then it is unspecified which of the two operands is
returned as the result. */
DEF_RTL_EXPR(SMIN, "smin", "ee", RTX_COMM_ARITH)
DEF_RTL_EXPR(SMAX, "smax", "ee", RTX_COMM_ARITH)
DEF_RTL_EXPR(UMIN, "umin", "ee", RTX_COMM_ARITH)
DEF_RTL_EXPR(UMAX, "umax", "ee", RTX_COMM_ARITH)
So, if _mm*_{min,max}_ss has the same requirement on what exactly should be
returned when both operands are zero or if either operand is NaN, then we
probably need to use an UNSPEC unless -ffast-math tells us NaNs won't appear or
sign of zero doesn't matter.