Date: Mon, 12 Nov 2012 00:07:46 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Dimitry Andric <dim@freebsd.org> Cc: Konstantin Belousov <kostikbel@gmail.com>, svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r242879 - in head/lib: libc/gen msun/src Message-ID: <20121111230817.G1155@besplex.bde.org> In-Reply-To: <509ED25E.3070302@FreeBSD.org> References: <201211102122.qAALMAnO014246@svn.freebsd.org> <20121110214345.GT73505@kib.kiev.ua> <509ED25E.3070302@FreeBSD.org>
next in thread | previous in thread | raw e-mail | index | archive | help
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 - the same warning is printed for -ffreestanding, but these functions are not reserved by C99 then. 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, 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. 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). 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). 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. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121111230817.G1155>