Bug 294214 - clang builtin functions break libm
Summary: clang builtin functions break libm
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 16.0-CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL: https://reviews.freebsd.org/D56230
Keywords:
Depends on:
Blocks:
 
Reported: 2026-04-02 20:09 UTC by Steve Kargl
Modified: 2026-04-13 17:43 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steve Kargl freebsd_committer freebsd_triage 2026-04-02 20:09:56 UTC
It has been brought to my attention that the use of some
clang builtin functions break libm.  Consider,

#include <math.h>
#include <stdio.h>

int
main(void)
{
   double f, x, y;

   x = 0.;
   y = copysign(x, -1.);
   printf("fmax(% lf % lf) = % lf\n", x, x, fmax(x,x));
   printf("fmax(% lf % lf) = % lf\n", x, y, fmax(x,y));
   printf("fmax(% lf % lf) = % lf\n", y, x, fmax(y,x));

   return (0);
}

% cc -o z fmax.c -lm && ./z
fmax( 0.000000  0.000000) =  0.000000
fmax( 0.000000 -0.000000) =  0.000000
fmax(-0.000000  0.000000) = -0.000000  <--- this is wrong

% cc -o z fmax.c -lm -fno-builtin && ./z
fmax( 0.000000  0.000000) =  0.000000
fmax( 0.000000 -0.000000) =  0.000000
fmax(-0.000000  0.000000) =  0.000000

% gcc15 -o z fmax.c -lm && ./z
fmax( 0.000000  0.000000) =  0.000000
fmax( 0.000000 -0.000000) =  0.000000
fmax(-0.000000  0.000000) =  0.000000  <--- this is correct

% -o z fmax.c -lm -fno-builtin && ./z
fmax( 0.000000  0.000000) =  0.000000
fmax( 0.000000 -0.000000) =  0.000000
fmax(-0.000000  0.000000) =  0.000000

The FreeBSD documentation has

% man fmax
...
DESCRIPTION
   The fmax(), fmaxf(), and fmaxl() functions return the larger of x and y,
   and likewise, the fmin(), fminf(), and fminl() functions return the
   smaller of x and y.  They treat +0.0 as being larger than -0.0.
Comment 1 Robert Clausecker freebsd_committer freebsd_triage 2026-04-02 20:27:31 UTC
This is the same story as memcmp().  The C standard does not specify whether +0 or -0 is returned if the two are passed to fmax() or fmin() and compilers will optimise this.

We should instead document that our libm supports a stricter behaviour than what
the C standard guarantees (as we did with memcmp()) and recommend that users pass
-fno-builtin-fmax and -fno-builtin-fmin or use one of the new C23 functions if they wish to have the stricter behaviour guaranteed.
Comment 2 Robert Clausecker freebsd_committer freebsd_triage 2026-04-02 20:30:01 UTC
In particular, I do not believe that this is a fight we can win, and we should pick our battles.  We cannot patch every single C compiler to obey our stricter interpretation of the C standard and users might not actually want this, as the stricter behaviour is slower than he more lenient behaviour guaranteed by the standard, and should never be required by portable applications.
Comment 3 Steve Kargl freebsd_committer freebsd_triage 2026-04-02 21:21:11 UTC
(In reply to Robert Clausecker from comment #2)

I suppose that a BUGS or CAVEAT section is the best
that we can do.  I suspect most users don't care 
about 0 vs -0; and those that do will already have
dealt with various compiler behaviors.
Comment 4 Steve Kargl freebsd_committer freebsd_triage 2026-04-02 22:13:45 UTC
Ed, I saw the D56230.  Looks ok to me.  You may want to add
something like:

  Some compiler enable one to disable optimizations via 
  command-line optimizations such as -fno-builtin-fmax
  and -fno-builtin-fmin.

I'll leave it to you and/or Robert to decide whether
a hint is needed.
Comment 5 Steve Kargl freebsd_committer freebsd_triage 2026-04-02 22:15:34 UTC
(In reply to Steve Kargl from comment #4)

Ugh, that was some torched English.

  Some compiler allow one to disable optimizations via 
  command-line options such as -fno-builtin-fmax and
  -fno-builtin-fmin.
Comment 6 Steve Kargl freebsd_committer freebsd_triage 2026-04-03 01:45:28 UTC
Ugh*ugh.

The addition of '#pragma STDC FENV_ACCESS ON' changes
clang's to agree with fmax(3).


% cc -o z fmax.c -lm && ./z
fmax( 0,  0) =  0 expecting  0
fmax(-0,  0) = -0 expecting  0 <-- FAILED
fmax( 0, -0) =  0 expecting  0
fmax(-0, -0) = -0 expecting -0


% cc -o z fmax.c -DWITH_PRAGMA -lm && ./z
fmax( 0,  0) =  0 expecting  0
fmax(-0,  0) =  0 expecting  0
fmax( 0, -0) =  0 expecting  0
fmax(-0, -0) = -0 expecting -0
Comment 7 commit-hook freebsd_committer freebsd_triage 2026-04-06 17:00:35 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=7764e9ca28a9702aed4ba7391e055ec2fcf35c41

commit 7764e9ca28a9702aed4ba7391e055ec2fcf35c41
Author:     Ed Maste <emaste@FreeBSD.org>
AuthorDate: 2026-04-02 21:59:42 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2026-04-06 17:00:15 +0000

    fmax.3: Add caveat for going beyond C std requirements

    libm's fmax and fmin family of functions treat +0.0 as greater than
    -0.0.  This is not required by the C standard, so the user may not see
    this behaviour due to compiler optimization.

    PR:             294214
    Reviewed by:    fuz
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D56230

 lib/msun/man/fmax.3 | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
Comment 8 commit-hook freebsd_committer freebsd_triage 2026-04-13 17:36:50 UTC
A commit in branch stable/15 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=855507463e0d3903d31aa7c084efbf4f819b5d63

commit 855507463e0d3903d31aa7c084efbf4f819b5d63
Author:     Ed Maste <emaste@FreeBSD.org>
AuthorDate: 2026-04-02 21:59:42 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2026-04-13 17:35:35 +0000

    fmax.3: Add caveat for going beyond C std requirements

    libm's fmax and fmin family of functions treat +0.0 as greater than
    -0.0.  This is not required by the C standard, so the user may not see
    this behaviour due to compiler optimization.

    PR:             294214
    Reviewed by:    fuz
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D56230

    (cherry picked from commit 7764e9ca28a9702aed4ba7391e055ec2fcf35c41)

 lib/msun/man/fmax.3 | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
Comment 9 commit-hook freebsd_committer freebsd_triage 2026-04-13 17:43:53 UTC
A commit in branch stable/14 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=dc61491025091d9e61048cc3cfb18d25ed354a8b

commit dc61491025091d9e61048cc3cfb18d25ed354a8b
Author:     Ed Maste <emaste@FreeBSD.org>
AuthorDate: 2026-04-02 21:59:42 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2026-04-13 17:43:05 +0000

    fmax.3: Add caveat for going beyond C std requirements

    libm's fmax and fmin family of functions treat +0.0 as greater than
    -0.0.  This is not required by the C standard, so the user may not see
    this behaviour due to compiler optimization.

    PR:             294214
    Reviewed by:    fuz
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D56230

    (cherry picked from commit 7764e9ca28a9702aed4ba7391e055ec2fcf35c41)
    (cherry picked from commit 855507463e0d3903d31aa7c084efbf4f819b5d63)

 lib/msun/man/fmax.3 | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)