Blame sysdeps/i386/fpu/e_powl.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 p2,@object
Packit 6c4009
p2:	.byte 0, 0, 0, 0, 0, 0, 0x10, 0x40
Packit 6c4009
	ASM_SIZE_DIRECTIVE(p2)
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 p64,@object
Packit 6c4009
p64:	.byte 0, 0, 0, 0, 0, 0, 0xf0, 0x43
Packit 6c4009
	ASM_SIZE_DIRECTIVE(p64)
Packit 6c4009
	.type p78,@object
Packit 6c4009
p78:	.byte 0, 0, 0, 0, 0, 0, 0xd0, 0x44
Packit 6c4009
	ASM_SIZE_DIRECTIVE(p78)
Packit 6c4009
	.type pm79,@object
Packit 6c4009
pm79:	.byte 0, 0, 0, 0, 0, 0, 0, 0x3b
Packit 6c4009
	ASM_SIZE_DIRECTIVE(pm79)
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_LDBL_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_powl)
Packit 6c4009
	fldt	16(%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
	fldt	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
	je	9f
Packit 6c4009
Packit 6c4009
	// If y has absolute value at most 0x1p-79, then any finite
Packit 6c4009
	// nonzero x will result in 1.  Saturate y to those bounds to
Packit 6c4009
	// avoid underflow in the calculation of y*log2(x).
Packit 6c4009
	fld	%st		// y : y : x
Packit 6c4009
	fabs			// |y| : y : x
Packit 6c4009
	fcompl	MO(pm79)	// y : x
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	3f
Packit 6c4009
	fstp	%st(0)		// pop y
Packit 6c4009
	fldl	MO(pm79)	// 0x1p-79 : x
Packit 6c4009
	testb	$2, %dl
Packit 6c4009
	jnz	3f		// y > 0
Packit 6c4009
	fchs			// -0x1p-79 : x
Packit 6c4009
	jmp	3f
Packit 6c4009
Packit 6c4009
9:	/* OK, we have an integer value for y.  Unless very small
Packit 6c4009
	   (we use < 4), use the algorithm for real exponent to avoid
Packit 6c4009
	   accumulation of errors.  */
Packit 6c4009
	fld	%st		// y : y : x
Packit 6c4009
	fabs			// |y| : y : x
Packit 6c4009
	fcompl	MO(p2)		// y : x
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	3f
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
	LDBL_CHECK_FORCE_UFLOW_NONNAN
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	/* y is ±NAN */
Packit 6c4009
30:	fldt	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	33f
Packit 6c4009
31:	/* At least one argument NaN, and result should be NaN.  */
Packit 6c4009
	faddp
Packit 6c4009
	ret
Packit 6c4009
33:	jp	31b
Packit 6c4009
	/* pow (1, NaN); check if the NaN signaling.  */
Packit 6c4009
	testb	$0x40, 23(%esp)
Packit 6c4009
	jz	31b
Packit 6c4009
	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
	faddp
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<<63).
Packit 6c4009
	// If y has absolute value at least 1L<<78, then any finite
Packit 6c4009
	// nonzero x will result in 0 (underflow), 1 or infinity (overflow).
Packit 6c4009
	// Saturate y to those bounds to avoid overflow in the calculation
Packit 6c4009
	// of y*log2(x).
Packit 6c4009
	fld	%st		// y : y : x
Packit 6c4009
	fabs			// |y| : y : x
Packit 6c4009
	fcompl	MO(p78)		// y : x
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jc	3f
Packit 6c4009
	fstp	%st(0)		// pop y
Packit 6c4009
	fldl	MO(p78)		// 1L<<78 : x
Packit 6c4009
	testb	$2, %dl
Packit 6c4009
	jz	3f		// y > 0
Packit 6c4009
	fchs			// -(1L<<78) : x
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
3:	/* y is a real number.  */
Packit 6c4009
	subl	$28, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (28)
Packit 6c4009
	fstpt	12(%esp)	// x
Packit 6c4009
	fstpt	(%esp)		// <empty>
Packit 6c4009
	call	HIDDEN_JUMPTARGET (__powl_helper)	// <result>
Packit 6c4009
	addl	$36, %esp
Packit 6c4009
	cfi_adjust_cfa_offset (-36)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
	// pow(x,±0) = 1, unless x is sNaN
Packit 6c4009
	.align ALIGNARG(4)
Packit 6c4009
11:	fstp	%st(0)		// pop y
Packit 6c4009
	fldt	4(%esp)		// x
Packit 6c4009
	fxam
Packit 6c4009
	fnstsw
Packit 6c4009
	andb	$0x45, %ah
Packit 6c4009
	cmpb	$0x01, %ah
Packit 6c4009
	je	112f		// x is NaN
Packit 6c4009
111:	fstp	%st(0)
Packit 6c4009
	fldl	MO(one)
Packit 6c4009
	ret
Packit 6c4009
Packit 6c4009
112:	testb	$0x40, 11(%esp)
Packit 6c4009
	jnz	111b
Packit 6c4009
	fadd	%st(0)
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
	fldt	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:	fldt	4(%esp)		// load x == NaN
Packit 6c4009
	fadd	%st(0)
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, but y
Packit 6c4009
	// may be odd unless we know |y| >= 1L<<64.
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fabs			// |y| : y
Packit 6c4009
	fcompl	MO(p64)		// y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	16f
Packit 6c4009
	fldl	MO(p63)		// p63 : y
Packit 6c4009
	fxch			// y : p63
Packit 6c4009
	fprem			// y%p63 : p63
Packit 6c4009
	fstp	%st(1)		// y%p63
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, 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	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, but y
Packit 6c4009
	// may be odd unless we know |y| >= 1L<<64.
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fabs			// |y| : y
Packit 6c4009
	fcompl	MO(p64)		// y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	25f
Packit 6c4009
	fldl	MO(p63)		// p63 : y
Packit 6c4009
	fxch			// y : p63
Packit 6c4009
	fprem			// y%p63 : p63
Packit 6c4009
	fstp	%st(1)		// y%p63
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, 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	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, but y
Packit 6c4009
	// may be odd unless we know |y| >= 1L<<64.
Packit 6c4009
	fld	%st		// y : y
Packit 6c4009
	fcompl	MO(p64)		// y
Packit 6c4009
	fnstsw
Packit 6c4009
	sahf
Packit 6c4009
	jnc	22f
Packit 6c4009
	fldl	MO(p63)		// p63 : y
Packit 6c4009
	fxch			// y : p63
Packit 6c4009
	fprem			// y%p63 : p63
Packit 6c4009
	fstp	%st(1)		// y%p63
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, 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	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_powl)
Packit 6c4009
strong_alias (__ieee754_powl, __powl_finite)