summaryrefslogtreecommitdiff
path: root/sysdeps/libm-i387/e_scalb.S
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/libm-i387/e_scalb.S')
-rw-r--r--sysdeps/libm-i387/e_scalb.S78
1 files changed, 78 insertions, 0 deletions
diff --git a/sysdeps/libm-i387/e_scalb.S b/sysdeps/libm-i387/e_scalb.S
index 427a3b905e..790f1c1d56 100644
--- a/sysdeps/libm-i387/e_scalb.S
+++ b/sysdeps/libm-i387/e_scalb.S
@@ -1,16 +1,94 @@
/*
* Written by J.T. Conklin <jtc@netbsd.org>.
* Public domain.
+ *
+ * Correct handling of y==-inf <drepper@gnu>
*/
#include <machine/asm.h>
RCSID("$NetBSD: e_scalb.S,v 1.4 1995/05/08 23:49:52 jtc Exp $")
+#ifdef __ELF__
+ .section .rodata
+#else
+ .text
+#endif
+
+ .align ALIGNARG(4)
+ ASM_TYPE_DIRECTIVE(zero_nan,@object)
+zero_nan:
+ .double 0.0
+nan: .byte 0, 0, 0, 0, 0, 0, 0xff, 0x7f
+minus_zero:
+ .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##@GOTOFF(%ecx)
+#define MOX(op,x,f) op##@GOTOFF(%ecx,x,f)
+#else
+#define MO(op) op
+#define MOX(op,x,f) op(,x,f)
+#endif
+
+
ENTRY(__ieee754_scalb)
fldl 12(%esp)
+ fxam
+ fnstsw
fldl 4(%esp)
+ 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 2f
+ fld %st(1)
+ frndint
+ fcomp %st(2)
+ fnstsw
+ sahf
+ jne 2f
fscale
fstp %st(1)
ret
+
+ /* y is -inf */
+1: fxam
+#ifdef PIC
+ call 1f
+1: popl %ecx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx
+#endif
+ fnstsw
+ movl 8(%esp), %edx
+ shrl $5, %eax
+ fstp %st(1)
+ andl $0x80000000, %edx
+ andl $8, %eax
+ fstp %st(1)
+ shrl $27, %edx
+ addl %edx, %eax
+ fldl MOX(zero_nan, %eax, 1)
+ ret
+
+ /* The result is NaN, but we must not raise an exception.
+ So use a variable. */
+2: fstp %st
+ fstp %st
+#ifdef PIC
+ call 1f
+1: popl %ecx
+ addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx
+#endif
+ fldl MO(nan)
+ ret
END(__ieee754_scalb)