svn commit: r242879 - in head/lib: libc/gen msun/src

Dimitry Andric dim at FreeBSD.org
Sun Nov 11 15:11:39 UTC 2012


On 2012-11-11 14:07, Bruce Evans wrote:
> On Sat, 10 Nov 2012, Dimitry Andric wrote:
>> On 2012-11-10 22:43, Konstantin Belousov wrote:
>>> On Sat, Nov 10, 2012 at 09:22:10PM +0000, Dimitry Andric wrote:
>> ...
>>>> Author: dim
>>>> Date: Sat Nov 10 21:22:10 2012
>>>> New Revision: 242879
>>>> URL: http://svnweb.freebsd.org/changeset/base/242879
>>>>
>>>> Log:
>>>>     Only define isnan, isnanf, __isnan and __isnanf in libc.so, not in
>>>>     libc.a and libc_p.a.  In addition, define isnan in libm.a and libm_p.a,
>>>>     but not in libm.so.
>>>>
>>>>     This makes it possible to statically link executables using both isnan
>>>>     and isnanf with libc and libm.
>> ...
>>> So you broke ABI for libm ?
>>
>> No, both libc.so and libm.so are the same as before.  Only the .a files
>> are changed.
>>
>> I should probably have made the commit message more clear, sorry about
>> that.
>
> Hopefully "fixed" instead of "broke" (except the .so files are unchanged
> so they are still broken).  I use the hack of ifdefing out the definition
> of __isnanf() in libm.  isnan() is already ifdefed out there.  I didn't
> touch the compatibility cruft weak references to isnanf() there -- libc
> has it too, so it is not needed any more than isnan() here.
>
> The pessimality of these functions is another problem.  C99 only requires
> the isnan() API, and only requires it to be a macro.  gcc-4.2.1 and clang
> (but not gcc-3.3.3 which I often test with) provide good builtins for
> these functions.  But the FreeBSD implementation destroys use of the
> builtins with some help from the ABI:
> - if you compile isnan*(x) calls using gcc _without_ including <math.h>,
>     then everything works right -- they builtins are used and are optimal
> - if you compile isnan*(x) calls using gcc _without_ including <math.h>,
>     then you get annoying (and broken) warnings about implicit function
>     declarations being invalid in C99.  This is a bug in clang.  These
>     functions are reserved in C99, so some other warning for them would
>     be correct, but things warning is wrong in several ways:
>     - implicit function declarations are not invalid in C9

Implicit function declarations are invalid in C99, not in C89.  Clang
defaults to C99.  Whether the function is reserved or not, should not
matter.


>     - the same warning is printed for -ffreestanding, but these functions
>       are not reserved by C99 then.

Again, I don't agree.  Reserved or not is not relevant.  If the above
reasoning was followed, we would never have to include <stdio.h> either,
because all those prototypes would already be implicitly there? :-)


>     After turning off the broken warning using
>     -Wno-implicit-function-declarations, everything works right for these
>     function calls, but of course not for others for which you want this
>     warning.
> So for clang you must include <math.h> for calling these functions,

No, according to the C99 standard you must include <math.h>.  Quoting
7.12.3.4:

   Synopsis:

   #include <math.h>
   int isnan(real-floating  x);

The synopses of all math functions explicitly have the the #include at
the top.


> and
> of course for other FP library features, omitting the include is even
> more impractical.  This gives the pessimizations:
> - the isnan() macro translates to isnan() for doubles, __isnanf() for
>     floats and __isnanfl() for long doubles.  The null translation for
>     doubles gives the builtin and it works as above, but the other
>     translations give the library functions with their underscored
>     spelling.  Compilers don't understand this spelling, so they don't
>     give the builtins.  So isnan() is pessimized when applied to floats
>     and long doubles.

Yes, this is rather unfortunate.  Though I originally assumed that the
libm authors found all the compiler builtins inferior in some way, and
therefore supplied their own implementations. :-)


> OTOH, if you forget that isnan() is type-generic and spell it isnanf()
> or isnanl(), then the float and long double cases mostly work right
> again:
> - same behaviour if <math.h> is not included (and -O is used)
> - if <math.h> is included, then it declares isnanf() but not isnanl(),
>     since only the former is compatibility cruft and has an extern function.
>     So isnanf() always works and the builtin is always used with -O and
>     and the extern function is used without -O.  But isnanl() causes the
>     following problems:
>     - -Wimplicit* warning
>     - linkage failure without -O.
>
> Another problem is that the extern __isnanl() is broken on x86, but the
> builtin works.  The extern functions do bit tests that are rather slow
> but not slow enough to be correct (they don't check for pseudo-numbers
> which the hardware treats as NaNs), but the builtin does a simple x != x
> test which is probably optimal, and works.
>
> Similarly for some other macros (they convert to spelling that compilers
> don't understand, and at least the classification macros are broken on
> psudo-numbers, but now the broken cases are mostly ones for which the
> builtins don't exist or is broken).

In short, maybe just:

#define isnan __builtin_isnan

? That should cover all cases.  With a fallback for !gcc && !clang,
obviously.  The functions stay behind for backwards compatibility.


> Fixing the pessimizations would reduce the ABI problems.  Both libc
> and libm should translate to the builtin if it exists and is a real
> builtin (not a libcall).  This seems reasonable even without -O, since
> C99 doesn't require any functions to exist so nothing should take their
> addresses or try to call them as non-macros ('(isnan)(x)').  <math.h>
> already has complications to use builtins for 1 set of interfaces only.
> The only problems are that it is that it is hard to tell if builtins
> exist and are real (there are compiler predefines for the set that
> uses builtins but not for most sets).

How is it hard to tell?  Both gcc and clang support those builtins,
unless you want to support very old versions of gcc, which might not
have them.


> With this, the library functions are never used by new compiles and
> are only needed by old applications.  All static copies of them can
> be removed, but the .so ones are still needed until the ABI is changed.
>
> When will the library isnanf() have been deprecated long enough to
> remove in .so's too?  Maybe it never needed to be preserved, since
> old applications will link to old libraries that have it.

I don't think we can ever remove them from libc.so anymore, unless
version bumps are reintroduced. :-)


More information about the svn-src-all mailing list