On 2010-09-30 05:46, Bruce Evans wrote:
...
This file probably shouldn't exist, especially on amd64. There are 4 or 5
versions of ldexp(), and this file implements what seems to be the worst
one, even without the bug.
First, it shouldn't exist since it is a libm function. It exists for the
historical reason that its object file has always been in libc. This
causes organizational problems.
It also makes it impossible to throw it out of libc, as there are many
applications that expect it in there. Luckily, it seems to be only
ldexp for which this is the case, not ldexpl or ldexpf. :)
The second version is in fdlibm. This wasn't imported into FreeBSD. It
calls scalbn() after checking some cases. I think it shouldn't check
anything. In FreeBSD it could be a weak alias to scalbn().
The third version is in fdlibm. This one is named scalbn(). FreeBSD has
it. FreeBSD aliases ldexpl() to scalbn() iff long doubles are the same as
doubles. FreeBSD also has scalbnf(). This came from NetBSD/Cygnus's
extension of fdlibm. FreeBSD aliases ldexpf() to scalbnf() (or is it
the other way?).
We alias scalbnf() to ldexpf(), apparently.
The fourth version is in the FreeBSD arch-dependent directories of
lib/msun for at least amd64 and i386. These are also named scalbn().
These aren't in fdlibm, but came from NetBSD. These are written in
non-inline asm and are similar to the ones in libc. They are a couple
of instructions shorter, due to never using a frame pointer (unless
profiling) and avoiding an fxch or two. They aren't aliased to aything,
and don't have float versions.
The fifth version, which might not exist, is gcc's builtin. I think it
doesn't really exist, but gcc says it has a builtin ldexp() and I had to
fight with this to test this. gcc normally made the dubious optimization
of moving ldexp() out of a test loop. But ldexp() has side effects.
The version in libc/gen/ldexp.c is just a copy of msun/src/s_scalbn.c,
with some things like copysign() directly pasted in. It even has:
/* @(#)fdlibm.h 5.1 93/09/24 */
at the top.
Testing indicates that the fdlibm C version is 2.5 times faster than the
asm versions on amd64 on a core2 (ref9), while on i386 the C version is
only 1.5 times faster. The C code is a bit larger so benefits more from
being called from a loop. The asm code uses a slow i387 instruction, and
on i387 it hhs to do expensive moves from xmm registers to i387 ones and
back.
Times for 100 million calls:
amd64 libc ldexp: 3.18 seconds
amd64 libm asm scalbn: 2.96
amd64 libm C scalbn: 1.30
i386 libc ldexp: 3.13
i386 libm asm scalbn: 2.86
i386 libm C scalbn: 2.11
Seeing these results, I propose to just delete
lib/libc/amd64/gen/ldexp.c and lib/libc/i386/gen/ldexp.c, which will
cause the amd64 and i386 builds to automatically pick up
lib/libc/gen/ldexp.c instead, which effectively is the fdlibm
implementation. (And no more clang workarounds needed. :)
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"