[PATCH] math: Order signed zeros in fmin and fmax.

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Tue Dec 23 17:22:56 GMT 2025



On 23/12/25 14:06, Wilco Dijkstra wrote:
> Hi Adhemerval/James,
> 
>>> I believe the patch results in the desired behavior on all targets,
>>> even though it modifies only the i386, i686, x86_64, and the generic C
>>> implementation.
> 
> That's good to hear, it would be useful to mention something like that in the
> description.
> 
>> As a side note, I don't think there is much gain is having the i386 version.
>> If you a felling adventurous, maybe you can send a patch to just remove the
>> i386 variants and making the i686 the default one.
> 
> I think the same is true for the x86_64 version, with my proposed improvement
> below, it generates:
> 
> "__fmin":
>         ucomisd xmm0, xmm1
>         movapd  xmm2, xmm0
>         jp      .L14
>         je      .L29
>         minsd   xmm2, xmm1
>         movapd  xmm0, xmm2
>         ret
> 
> This is from writing fmin/fmax like this:
> 
>   if (!isunordered (x, y))
>   {
>     if (__glibc_unlikely (x == y))
>       return signbit (x) ? x : y;
>     return x < y ? x : y;
>   }
> 
> This has fewer operations and branches, and allows targets to use conditional moves
> or min/max in both return cases.
> 
> The only remaining issue with the generic C implementation is that we don't yet
> inline issignaling, so the NaN handling is slightly slower. If that is inlined then the
> i686 assembler implementation could likely be removed too.

We do have an inline implementation for __issignalingf on include/math.h
and math/math.h already have a proper TG_MATH call to issignaling.  So
I think should a matter to add a double variant and maybe a per-type
one on some sysdeps/ieee754/type/header.  

> 
>> The additional targets in glibc which don't use the generic C
>> implementation are:
>> - riscv
>> - loongarch (via setting USE_F{MIN,MAX}{,F}_BUILTIN)
>> - aarch64 (via setting USE_F{MIN,MAX}{,F}_BUILTIN)
>>
>> On these architectures, the operation is already implemented by a
>> single hardware instruction with the desired behavior; no changes are
>> required.
> 
> There are more, eg. power will emit "xsmindp" since power7 at least, but they don't
> seem to define USE_F{MIN,MAX}{,F}_BUILTIN.
> 
>>> There are at least
>>> 3 different variations of fmin/fmax in the IEEE standard, so I'm wondering whether
>>> they do agree on how to handle signed zeroes... If it works on all modern targets,
>>> that's great, but that's not clear from your description because ISAs typically
>>> follow IEEE specs.
>>
>> Yes, the other variations of floating-point min/max are fminimum,
>> fminimum_mag, fminimum_num, fminimum_mag_num (and their corresponding
>> maximums). Those functions are required to order signed zeros by the C
>> standard, unlike fmin/fmax where it is only recommended.
> 
> fminmag/fmaxmag currently don't order signed zeroes either:
> 
> FLOAT
> M_DECL_FUNC (__fminmag) (FLOAT x, FLOAT y)
> {
>   FLOAT ax = M_FABS (x);
>   FLOAT ay = M_FABS (y);
>   if (isless (ax, ay))
>     return x;
>   else if (isgreater (ax, ay))
>     return y;
>   else if (ax == ay)
>     return x < y ? x : y;
>   else if (issignaling (x) || issignaling (y))
>     return x + y;
>   else
>     return isnan (y) ? x : y;
> }
> 
> This one does do it, but inefficiently (there is also different NaN handling...):
> 
> FLOAT
> M_DECL_FUNC (__fminimum_mag_num) (FLOAT x, FLOAT y)
> {
>   FLOAT ax = M_FABS (x);
>   FLOAT ay = M_FABS (y);
>   if (isless (ax, ay))
>     return x;
>   else if (isgreater (ax, ay))
>     return y;
>   else if (ax == ay)
>     return (M_COPYSIGN (1, x) <= M_COPYSIGN (1, y) ? x : y);
>   else
>     return isnan (y) ? (isnan (x) ? x + y : x) : y;
> }
> 
> So it would be great to make them consistent for signed zero and use the same efficient
> sequence in all cases.
> 
> Cheers,
> Wilco



More information about the Libc-alpha mailing list