Blame sysdeps/i386/fpu/e_pow.S

Packit 6c4009
/* ix87 specific implementation of pow function.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <machine/asm.h>
Packit 6c4009
#include <i386-math-asm.h>
Packit 6c4009
Packit 6c4009
	.section .rodata.cst8,"aM",@progbits,8
Packit 6c4009
Packit 6c4009
	.p2align 3
Packit 6c4009
	.type one,@object
Packit 6c4009
one:	.double 1.0
Packit 6c4009
	ASM_SIZE_DIRECTIVE(one)
Packit 6c4009
	.type limit,@object
Packit 6c4009
limit:	.double 0.29
Packit 6c4009
	ASM_SIZE_DIRECTIVE(limit)
Packit 6c4009
	.type p63,@object
Packit 6c4009
p63:	.byte 0, 0, 0, 0, 0, 0, 0xe0, 0x43
Packit 6c4009
	ASM_SIZE_DIRECTIVE(p63)
Packit 6c4009
	.type p10,@object
Packit 6c4009
p10:	.byte 0, 0, 0, 0, 0, 0, 0x90, 0x40
Packit 6c4009
	ASM_SIZE_DIRECTIVE(p10)
Packit 6c4009
Packit 6c4009
	.section .rodata.cst16,"aM",@progbits,16
Packit 6c4009
Packit 6c4009
	.p2align 3
Packit 6c4009
	.type infinity,@object
Packit 6c4009
inf_zero:
Packit 6c4009
infinity:
Packit 6c4009
	.byte 0, 0, 0, 0, 0, 0, 0xf0, 0x7f
Packit 6c4009
	ASM_SIZE_DIRECTIVE(infinity)
Packit 6c4009
	.type zero,@object
Packit 6c4009
zero:	.double 0.0
Packit 6c4009
	ASM_SIZE_DIRECTIVE(zero)
Packit 6c4009
	.type minf_mzero,@object
Packit 6c4009
minf_mzero:
Packit 6c4009
minfinity:
Packit 6c4009
	.byte 0, 0, 0, 0, 0, 0, 0xf0, 0xff
Packit 6c4009
mzero:
Packit 6c4009
	.byte 0, 0, 0, 0, 0, 0, 0, 0x80
Packit 6c4009
	ASM_SIZE_DIRECTIVE(minf_mzero)
Packit 6c4009
DEFINE_DBL_MIN
Packit 6c4009
Packit 6c4009
#ifdef PIC
Packit 6c4009
# define MO(op) op##@GOTOFF(%ecx)
Packit 6c4009
# define MOX(op,x,f) op##@GOTOFF(%ecx,x,f)
Packit 6c4009
#else
Packit 6c4009
# define MO(op) op
Packit 6c4009
# define MOX(op,x,f) op(,x,f)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	.text
Packit 6c4009
ENTRY(__ieee754_pow)
Packit 6c4009
	fldl	12(%esp)	// y
Packit 6c4009
	fxam
Packit 6c4009
Packit 6c4009
#ifdef	PIC
Packit 6c4009
	LOAD_PIC_REG (cx)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	fnstsw
Packit 6c4009
	movb	%ah, %dl
Packit 6c4009
	andb	$0x45, %ah
Packit 6c4009
	cmpb	$0x40, %ah	// is y == 0 ?
Packit 6c4009
	je	11f
Packit 6c4009
Packit 6c4009
	cmpb	$0x05, %ah	// is y == ±inf ?
Packit 6c4009
	je	12f
Packit 6c4009
Packit 6c4009
	cmpb	$0x01, %ah	// is y == NaN ?
Packit 6c4009
	je	30f
Packit 6c4009
Packit 6c4009
	fldl	4(%esp)		// x : y
Packit 6c4009
Packit 6c4009
	subl	$8,%esp
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
Packit 6c4009
	fxam
Packit 6c4009
	fnstsw
Packit 6c4009
	movb	%ah, %dh
Packit 6c4009
	andb	$0x45, %ah
Packit 6c4009
	cmpb	$0x40, %ah
Packit 6c4009
	je	20f		// x is ±0
Packit 6c4009
Packit 6c4009
	cmpb	$0x05, %ah
Packit 6c4009
	je	15f		// x is ±inf
Packit 6c4009
Packit 6c4009
	cmpb	$0x01, %ah
Packit 6c4009
	je	32f		// x is NaN
Packit 6c4009
Packit 6c4009
	fxch			// y : x
Packit 6c4009
Packit 6c4009
	/* fistpll raises invalid exception for |y| >= 1L<<63.  */
Packit 6c4009
	fld	%st		// y : y : x
Packit 6c4009
	fabs			// |y| : y : x
Packit 6c4009
	fcompl	MO(p63)		// y : x
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	2f
Packit 6c4009
Packit 6c4009
	/* First see whether `y' is a natural number.  In this case we
Packit 6c4009
	   can use a more precise algorithm.  */
Packit 6c4009
	fld	%st		// y : y : x
Packit 6c4009
	fistpll	(%esp)		// y : x
Packit 6c4009
	fildll	(%esp)		// int(y) : y : x
Packit 6c4009
	fucomp	%st(1)		// y : x
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jne	3f
Packit 6c4009
Packit 6c4009
	/* OK, we have an integer value for y.  If large enough that
Packit 6c4009
	   errors may propagate out of the 11 bits excess precision, use
Packit 6c4009
	   the algorithm for real exponent instead.  */
Packit 6c4009
	fld	%st		// y : y : x
Packit 6c4009
	fabs			// |y| : y : x
Packit 6c4009
	fcompl	MO(p10)		// y : x
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	2f
Packit 6c4009
	popl	%eax
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	popl	%edx
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	orl	$0, %edx
Packit 6c4009
	fstp	%st(0)		// x
Packit 6c4009
	jns	4f		// y >= 0, jump
Packit 6c4009
	fdivrl	MO(one)		// 1/x		(now referred to as x)
Packit 6c4009
	negl	%eax
Packit 6c4009
	adcl	$0, %edx
Packit 6c4009
	negl	%edx
Packit 6c4009
4:	fldl	MO(one)		// 1 : x
Packit 6c4009
	fxch
Packit 6c4009
Packit 6c4009
	/* If y is even, take the absolute value of x.  Otherwise,
Packit 6c4009
	   ensure all intermediate values that might overflow have the
Packit 6c4009
	   sign of x.  */
Packit 6c4009
	testb	$1, %al
Packit 6c4009
	jnz	6f
Packit 6c4009
	fabs
Packit 6c4009
Packit 6c4009
6:	shrdl	$1, %edx, %eax
Packit 6c4009
	jnc	5f
Packit 6c4009
	fxch
Packit 6c4009
	fabs
Packit 6c4009
	fmul	%st(1)		// x : ST*x
Packit 6c4009
	fxch
Packit 6c4009
5:	fld	%st		// x : x : ST*x
Packit 6c4009
	fabs			// |x| : x : ST*x
Packit 6c4009
	fmulp			// |x|*x : ST*x
Packit 6c4009
	shrl	$1, %edx
Packit 6c4009
	movl	%eax, %ecx
Packit 6c4009
	orl	%edx, %ecx
Packit 6c4009
	jnz	6b
Packit 6c4009
	fstp	%st(0)		// ST*x
Packit 6c4009
#ifdef	PIC
Packit 6c4009
	LOAD_PIC_REG (cx)
Packit 6c4009
#endif
Packit 6c4009
	DBL_NARROW_EVAL_UFLOW_NONNAN
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	/* y is ±NAN */
Packit 6c4009
30:	fldl	4(%esp)		// x : y
Packit 6c4009
	fldl	MO(one)		// 1.0 : x : y
Packit 6c4009
	fucomp	%st(1)		// x : y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	je	31f
Packit 6c4009
	fxch			// y : x
Packit 6c4009
31:	fstp	%st(1)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
32:	addl	$8, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (-8)
Packit 6c4009
	fstp	%st(1)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
2:	// y is a large integer (absolute value at least 1L<<10), but
Packit 6c4009
	// may be odd unless at least 1L<<64.  So it may be necessary
Packit 6c4009
	// to adjust the sign of a negative result afterwards.
Packit 6c4009
	fxch			// x : y
Packit 6c4009
	fabs			// |x| : y
Packit 6c4009
	fxch			// y : x
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
3:	/* y is a real number.  */
Packit 6c4009
	fxch			// x : y
Packit 6c4009
	fldl	MO(one)		// 1.0 : x : y
Packit 6c4009
	fldl	MO(limit)	// 0.29 : 1.0 : x : y
Packit 6c4009
	fld	%st(2)		// x : 0.29 : 1.0 : x : y
Packit 6c4009
	fsub	%st(2)		// x-1 : 0.29 : 1.0 : x : y
Packit 6c4009
	fabs			// |x-1| : 0.29 : 1.0 : x : y
Packit 6c4009
	fucompp			// 1.0 : x : y
Packit 6c4009
	fnstsw
Packit 6c4009
	fxch			// x : 1.0 : y
Packit 6c4009
	sahf
Packit 6c4009
	ja	7f
Packit 6c4009
	fsub	%st(1)		// x-1 : 1.0 : y
Packit 6c4009
	fyl2xp1			// log2(x) : y
Packit 6c4009
	jmp	8f
Packit 6c4009
Packit 6c4009
7:	fyl2x			// log2(x) : y
Packit 6c4009
8:	fmul	%st(1)		// y*log2(x) : y
Packit 6c4009
	fst	%st(1)		// y*log2(x) : y*log2(x)
Packit 6c4009
	frndint			// int(y*log2(x)) : y*log2(x)
Packit 6c4009
	fsubr	%st, %st(1)	// int(y*log2(x)) : fract(y*log2(x))
Packit 6c4009
	fxch			// fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	f2xm1			// 2^fract(y*log2(x))-1 : int(y*log2(x))
Packit 6c4009
	faddl	MO(one)		// 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
Packit 6c4009
	// Before scaling, we must negate if x is negative and y is an
Packit 6c4009
	// odd integer.
Packit 6c4009
	testb	$2, %dh
Packit 6c4009
	jz	291f
Packit 6c4009
	// x is negative.  If y is an odd integer, negate the result.
Packit 6c4009
	fldl	20(%esp)	// y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fld	%st		// y : y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fabs			// |y| : y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fcompl	MO(p63)		// y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	290f
Packit 6c4009
Packit 6c4009
	// We must find out whether y is an odd integer.
Packit 6c4009
	fld	%st		// y : y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fistpll	(%esp)		// y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fildll	(%esp)		// int(y) : y : 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fucompp			// 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jne	291f
Packit 6c4009
Packit 6c4009
	// OK, the value is an integer, but is it odd?
Packit 6c4009
	popl	%eax
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	popl	%edx
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	andb	$1, %al
Packit 6c4009
	jz	292f		// jump if not odd
Packit 6c4009
	// It's an odd integer.
Packit 6c4009
	fchs
Packit 6c4009
	jmp	292f
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
290:	fstp	%st(0)		// 2^fract(y*log2(x)) : int(y*log2(x))
Packit 6c4009
291:	addl	$8, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (-8)
Packit 6c4009
292:	fscale			// +/- 2^fract(y*log2(x))*2^int(y*log2(x)) : int(y*log2(x))
Packit 6c4009
	fstp	%st(1)		// +/- 2^fract(y*log2(x))*2^int(y*log2(x))
Packit 6c4009
	DBL_NARROW_EVAL_UFLOW_NONNAN
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
Packit 6c4009
	// pow(x,±0) = 1
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
11:	fstp	%st(0)		// pop y
Packit 6c4009
	fldl	MO(one)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	// y == ±inf
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
12:	fstp	%st(0)		// pop y
Packit 6c4009
	fldl	MO(one)		// 1
Packit 6c4009
	fldl	4(%esp)		// x : 1
Packit 6c4009
	fabs			// abs(x) : 1
Packit 6c4009
	fucompp			// < 1, == 1, or > 1
Packit 6c4009
	fnstsw
Packit 6c4009
	andb	$0x45, %ah
Packit 6c4009
	cmpb	$0x45, %ah
Packit 6c4009
	je	13f		// jump if x is NaN
Packit 6c4009
Packit 6c4009
	cmpb	$0x40, %ah
Packit 6c4009
	je	14f		// jump if |x| == 1
Packit 6c4009
Packit 6c4009
	shlb	$1, %ah
Packit 6c4009
	xorb	%ah, %dl
Packit 6c4009
	andl	$2, %edx
Packit 6c4009
	fldl	MOX(inf_zero, %edx, 4)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
14:	fldl	MO(one)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
13:	fldl	4(%esp)		// load x == NaN
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
	// x is ±inf
Packit 6c4009
15:	fstp	%st(0)		// y
Packit 6c4009
	testb	$2, %dh
Packit 6c4009
	jz	16f		// jump if x == +inf
Packit 6c4009
Packit 6c4009
	// fistpll raises invalid exception for |y| >= 1L<<63, so test
Packit 6c4009
	// that (in which case y is certainly even) before testing
Packit 6c4009
	// whether y is odd.
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fabs			// |y| : y
Packit 6c4009
	fcompl	MO(p63)		// y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	16f
Packit 6c4009
Packit 6c4009
	// We must find out whether y is an odd integer.
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fistpll	(%esp)		// y
Packit 6c4009
	fildll	(%esp)		// int(y) : y
Packit 6c4009
	fucompp			// <empty>
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jne	17f
Packit 6c4009
Packit 6c4009
	// OK, the value is an integer.
Packit 6c4009
	popl	%eax
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	popl	%edx
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	andb	$1, %al
Packit 6c4009
	jz	18f		// jump if not odd
Packit 6c4009
	// It's an odd integer.
Packit 6c4009
	shrl	$31, %edx
Packit 6c4009
	fldl	MOX(minf_mzero, %edx, 8)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
16:	fcompl	MO(zero)
Packit 6c4009
	addl	$8, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (-8)
Packit 6c4009
	fnstsw
Packit 6c4009
	shrl	$5, %eax
Packit 6c4009
	andl	$8, %eax
Packit 6c4009
	fldl	MOX(inf_zero, %eax, 1)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
17:	shll	$30, %edx	// sign bit for y in right position
Packit 6c4009
	addl	$8, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (-8)
Packit 6c4009
18:	shrl	$31, %edx
Packit 6c4009
	fldl	MOX(inf_zero, %edx, 8)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
	// x is ±0
Packit 6c4009
20:	fstp	%st(0)		// y
Packit 6c4009
	testb	$2, %dl
Packit 6c4009
	jz	21f		// y > 0
Packit 6c4009
Packit 6c4009
	// x is ±0 and y is < 0.  We must find out whether y is an odd integer.
Packit 6c4009
	testb	$2, %dh
Packit 6c4009
	jz	25f
Packit 6c4009
Packit 6c4009
	// fistpll raises invalid exception for |y| >= 1L<<63, so test
Packit 6c4009
	// that (in which case y is certainly even) before testing
Packit 6c4009
	// whether y is odd.
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fabs			// |y| : y
Packit 6c4009
	fcompl	MO(p63)		// y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	25f
Packit 6c4009
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fistpll	(%esp)		// y
Packit 6c4009
	fildll	(%esp)		// int(y) : y
Packit 6c4009
	fucompp			// <empty>
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jne	26f
Packit 6c4009
Packit 6c4009
	// OK, the value is an integer.
Packit 6c4009
	popl	%eax
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	popl	%edx
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	andb	$1, %al
Packit 6c4009
	jz	27f		// jump if not odd
Packit 6c4009
	// It's an odd integer.
Packit 6c4009
	// Raise divide-by-zero exception and get minus infinity value.
Packit 6c4009
	fldl	MO(one)
Packit 6c4009
	fdivl	MO(zero)
Packit 6c4009
	fchs
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
25:	fstp	%st(0)
Packit 6c4009
26:	addl	$8, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (-8)
Packit 6c4009
27:	// Raise divide-by-zero exception and get infinity value.
Packit 6c4009
	fldl	MO(one)
Packit 6c4009
	fdivl	MO(zero)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
	// x is ±0 and y is > 0.  We must find out whether y is an odd integer.
Packit 6c4009
21:	testb	$2, %dh
Packit 6c4009
	jz	22f
Packit 6c4009
Packit 6c4009
	// fistpll raises invalid exception for |y| >= 1L<<63, so test
Packit 6c4009
	// that (in which case y is certainly even) before testing
Packit 6c4009
	// whether y is odd.
Packit 6c4009
	fcoml	MO(p63)		// y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	22f
Packit 6c4009
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fistpll	(%esp)		// y
Packit 6c4009
	fildll	(%esp)		// int(y) : y
Packit 6c4009
	fucompp			// <empty>
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jne	23f
Packit 6c4009
Packit 6c4009
	// OK, the value is an integer.
Packit 6c4009
	popl	%eax
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	popl	%edx
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	andb	$1, %al
Packit 6c4009
	jz	24f		// jump if not odd
Packit 6c4009
	// It's an odd integer.
Packit 6c4009
	fldl	MO(mzero)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	cfi_adjust_cfa_offset (8)
Packit 6c4009
22:	fstp	%st(0)
Packit 6c4009
23:	addl	$8, %esp	// Don't use 2 x pop
Packit 6c4009
	cfi_adjust_cfa_offset (-8)
Packit 6c4009
24:	fldl	MO(zero)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
END(__ieee754_pow)
Packit 6c4009
strong_alias (__ieee754_pow, __pow_finite)