summaryrefslogtreecommitdiff
path: root/lib/libm/arch
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2005-11-15 20:41:36 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2005-11-15 20:41:36 +0000
commita264dff2442a60964cbf2c4585b92128a2ce3d97 (patch)
tree867de300c929711e0e052ca8d76d3e70d9da324e /lib/libm/arch
parent17af9534d85f69d406b6d05d5ecd1d3a866ccc38 (diff)
Fix exp(3) for arg Inf and -Inf. From NetBSD; PR 4578. ok deraadt@
Diffstat (limited to 'lib/libm/arch')
-rw-r--r--lib/libm/arch/i387/e_exp.S118
1 files changed, 105 insertions, 13 deletions
diff --git a/lib/libm/arch/i387/e_exp.S b/lib/libm/arch/i387/e_exp.S
index bc1b34652cb..e4ec1de95e1 100644
--- a/lib/libm/arch/i387/e_exp.S
+++ b/lib/libm/arch/i387/e_exp.S
@@ -1,35 +1,127 @@
-/* $OpenBSD: e_exp.S,v 1.5 2005/08/02 11:17:31 espie Exp $ */
+/* $OpenBSD: e_exp.S,v 1.6 2005/11/15 20:41:35 otto Exp $ */
+/* $NetBSD: e_exp.S,v 1.12 2002/02/27 16:32:46 christos Exp $ */
+
/*
- * Written by J.T. Conklin <jtc@netbsd.org>.
- * Public domain.
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Written by:
+ * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc.
*/
#include <machine/asm.h>
/* e^x = 2^(x * log2(e)) */
ENTRY(__ieee754_exp)
- subl $8,%esp
-
- fstcw 4(%esp) /* store fpu control word */
- movw 4(%esp),%dx
+#ifndef __i386__
+ /*
+ * XXX: This code is broken and needs to be merged with the i386 case.
+ */
+ fstcw -12(%rsp)
+ movw -12(%rsp),%dx
orw $0x0180,%dx
- movw %dx,(%esp)
- fldcw (%esp) /* load modfied control word */
+ movw %dx,-16(%rsp)
+ fldcw -16(%rsp)
+ movsd %xmm0,-8(%rsp)
+ fldl -8(%rsp)
- fldl 12(%esp)
fldl2e
fmulp /* x * log2(e) */
- fst %st(1)
+ fld %st(0)
frndint /* int(x * log2(e)) */
fxch %st(1)
fsub %st(1),%st /* fract(x * log2(e)) */
+ f2xm1 /* 2^(fract(x * log2(e))) - 1 */
+ fld1
+ faddp /* 2^(fract(x * log2(e))) */
+ fscale /* e^x */
+ fstp %st(1)
+
+ fstpl -8(%rsp)
+ movsd -8(%rsp),%xmm0
+ fldcw -12(%rsp)
+ ret
+#else
+ /*
+ * If x is +-Inf, then the subtraction would give Inf-Inf = NaN.
+ * Avoid this. Also avoid it if x is NaN for convenience.
+ */
+ movl 8(%esp),%eax
+ andl $0x7fffffff,%eax
+ cmpl $0x7ff00000,%eax
+ jae x_Inf_or_NaN
+
+ fldl 4(%esp)
+
+ /*
+ * Ensure that the rounding mode is to nearest (to give the smallest
+ * possible fraction) and that the precision is as high as possible.
+ * We may as well mask interrupts if we switch the mode.
+ */
+ fstcw 4(%esp)
+ movl 4(%esp),%eax
+ andl $0x0300,%eax
+ cmpl $0x0300,%eax /* RC == 0 && PC == 3? */
+ je 1f /* jump if mode is good */
+ movl $0x137f,8(%esp)
+ fldcw 8(%esp)
+1:
+ fldl2e
+ fmulp /* x * log2(e) */
+ fst %st(1)
+ frndint /* int(x * log2(e)) */
+ fst %st(2)
+ fsubrp /* fract(x * log2(e)) */
f2xm1 /* 2^(fract(x * log2(e))) - 1 */
fld1
faddp /* 2^(fract(x * log2(e))) */
fscale /* e^x */
fstp %st(1)
+ je 1f
+ fldcw 4(%esp)
+1:
+ ret
- fldcw 4(%esp) /* restore original control word */
+x_Inf_or_NaN:
+ /*
+ * Return 0 if x is -Inf. Otherwise just return x, although the
+ * C version would return (x + x) (Real Indefinite) if x is a NaN.
+ */
+ cmpl $0xfff00000,8(%esp)
+ jne x_not_minus_Inf
+ cmpl $0,4(%esp)
+ jne x_not_minus_Inf
+ fldz
+ ret
- addl $8,%esp
+x_not_minus_Inf:
+ fldl 4(%esp)
ret
+#endif