about summary refs log tree commit diff
path: root/sysdeps/libm-i387/e_scalbl.S
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/libm-i387/e_scalbl.S')
-rw-r--r--sysdeps/libm-i387/e_scalbl.S78
1 files changed, 78 insertions, 0 deletions
diff --git a/sysdeps/libm-i387/e_scalbl.S b/sysdeps/libm-i387/e_scalbl.S
index 3b746ad363..e272614acf 100644
--- a/sysdeps/libm-i387/e_scalbl.S
+++ b/sysdeps/libm-i387/e_scalbl.S
@@ -3,16 +3,94 @@
  * Public domain.
  *
  * Adapted for `long double' by Ulrich Drepper <drepper@cygnus.com>.
+ *
+ * Correct handling of y==-inf <drepper@gnu>
  */
 
 #include <machine/asm.h>
 
 RCSID("$NetBSD: $")
 
+#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_scalbl)
 	fldt	16(%esp)
+	fxam
+	fnstsw
 	fldt	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	12(%esp), %edx
+	shrl	$5, %eax
+	fstp	%st(1)
+	andl	$0x8000, %edx
+	andl	$8, %eax
+	fstp	%st(1)
+	shrl	$11, %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_scalbl)