9438b237ab
Various x86 / x86_64 versions of scalb / scalbf / scalbl produce spurious "invalid" exceptions for (qNaN, -Inf) arguments, because this is wrongly handled like (+/-Inf, -Inf) which *should* raise such an exception. (In fact the NaN case of the code determining whether to quietly return a zero or a NaN for second argument -Inf was accidentally dead since the code had been made to return a NaN with exception.) This patch fixes the code to do the proper test for an infinity as distinct from a NaN. (Since the existing code does nothing to distinguish qNaNs and sNaNs here, this patch doesn't either. If in future we systematically implement proper sNaN semantics following TS 18661-1:2014, there will be lots of bugs to address - Thomas found lots of issues with his patch <https://sourceware.org/ml/libc-ports/2013-04/msg00008.html> to add SNaN tests (which never went in and would now require significant reworking).) Tested for x86_64 and x86. Committed. [BZ #16783] * sysdeps/i386/fpu/e_scalb.S (__ieee754_scalb): Do not handle arguments (NaN, -Inf) the same as (+/-Inf, -Inf). * sysdeps/i386/fpu/e_scalbf.S (__ieee754_scalbf): Likewise. * sysdeps/i386/fpu/e_scalbl.S (__ieee754_scalbl): Likewise. * sysdeps/x86_64/fpu/e_scalbl.S (__ieee754_scalbl): Likewise. * math/libm-test.inc (scalb_test_data): Add more tests.
97 lines
1.5 KiB
ArmAsm
97 lines
1.5 KiB
ArmAsm
/*
|
|
* Written by J.T. Conklin <jtc@netbsd.org>.
|
|
* Public domain.
|
|
*
|
|
* Adapted for `long double' by Ulrich Drepper <drepper@cygnus.com>.
|
|
* Adapted for x86-64 by Andreas Jaeger <aj@suse.de>
|
|
*
|
|
* Correct handling of y==-inf <drepper@gnu>
|
|
*/
|
|
|
|
#include <machine/asm.h>
|
|
|
|
.section .rodata
|
|
|
|
.align ALIGNARG(4)
|
|
.type zero_nan,@object
|
|
zero_nan:
|
|
.double 0.0
|
|
nan: .byte 0, 0, 0, 0, 0, 0, 0xff, 0x7f
|
|
.byte 0, 0, 0, 0, 0, 0, 0, 0x80
|
|
.byte 0, 0, 0, 0, 0, 0, 0xff, 0x7f
|
|
ASM_SIZE_DIRECTIVE(zero_nan)
|
|
|
|
|
|
#ifdef PIC
|
|
# define MO(op) op##(%rip)
|
|
#else
|
|
# define MO(op) op
|
|
#endif
|
|
|
|
.text
|
|
ENTRY(__ieee754_scalbl)
|
|
fldt 24(%rsp)
|
|
fxam
|
|
fnstsw
|
|
fldt 8(%rsp)
|
|
andl $0x4700, %eax
|
|
cmpl $0x0700, %eax
|
|
je 1f
|
|
andl $0x4500, %eax
|
|
cmpl $0x0100, %eax
|
|
je 2f
|
|
fxam
|
|
fnstsw
|
|
andl $0x4500, %eax
|
|
cmpl $0x0100, %eax
|
|
je 3f
|
|
fld %st(1)
|
|
frndint
|
|
fcomip %st(2), %st
|
|
jne 4f
|
|
fscale
|
|
fstp %st(1)
|
|
ret
|
|
|
|
/* y is -inf */
|
|
1: fxam
|
|
fnstsw
|
|
movl 16(%rsp), %edx
|
|
shrl $5, %eax
|
|
fstp %st
|
|
fstp %st
|
|
andl $0x8000, %edx
|
|
andl $0x0228, %eax
|
|
cmpl $0x0028, %eax
|
|
je 4f
|
|
andl $8, %eax
|
|
shrl $11, %edx
|
|
addl %edx, %eax
|
|
#ifdef PIC
|
|
lea zero_nan(%rip),%rdx
|
|
fldl (%rdx,%rax,1)
|
|
#else
|
|
fldl zero_nan(%rax, 1)
|
|
#endif
|
|
ret
|
|
|
|
/* The result is NaN, but we must not raise an exception.
|
|
So use a variable. */
|
|
2: fstp %st
|
|
fstp %st
|
|
fldl MO(nan)
|
|
ret
|
|
|
|
/* The first parameter is a NaN. Return it. */
|
|
3: fstp %st(1)
|
|
ret
|
|
|
|
/* Return NaN and raise the invalid exception. */
|
|
4: fstp %st
|
|
fstp %st
|
|
fldz
|
|
fdiv %st
|
|
ret
|
|
END(__ieee754_scalbl)
|
|
strong_alias (__ieee754_scalbl, __scalbl_finite)
|