1/* ix87 specific implementation of arctanh function.
2   Copyright (C) 1996, 1999 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6   The GNU C Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either
9   version 2.1 of the License, or (at your option) any later version.
10
11   The GNU C Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with the GNU C Library; if not, write to the Free
18   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   02111-1307 USA.  */
20
21#include <machine/asm.h>
22
23#ifdef __ELF__
24	.section .rodata
25#else
26	.text
27#endif
28
29	.align ALIGNARG(4)
30	/* Please note that we use double values for 0.5 and 1.0.  These
31	   numbers have exact representations and so we don't get accuracy
32	   problems.  The advantage is that the code is simpler.  */
33	ASM_TYPE_DIRECTIVE(half,@object)
34half:	.double 0.5
35	ASM_SIZE_DIRECTIVE(half)
36	ASM_TYPE_DIRECTIVE(one,@object)
37one:	.double 1.0
38	ASM_SIZE_DIRECTIVE(one)
39	/* It is not important that this constant is precise.  It is only
40	   a value which is known to be on the safe side for using the
41	   fyl2xp1 instruction.  */
42	ASM_TYPE_DIRECTIVE(limit,@object)
43limit:	.double 0.29
44	ASM_SIZE_DIRECTIVE(limit)
45	.align ALIGNARG(4)
46	ASM_TYPE_DIRECTIVE(ln2_2,@object)
47ln2_2:	.tfloat 0.3465735902799726547086160
48	ASM_SIZE_DIRECTIVE(ln2_2)
49
50#ifdef PIC
51#define MO(op) op##@GOTOFF(%edx)
52#else
53#define MO(op) op
54#endif
55
56	.text
57ENTRY(__ieee754_atanhl)
58	movl	12(%esp), %ecx
59
60	movl	%ecx, %eax
61	andl	$0x7fff, %eax
62	cmpl	$0x7fff, %eax
63	je	5f
647:
65
66#ifdef PIC
67	call	1f
681:	popl	%edx
69	addl	$_GLOBAL_OFFSET_TABLE_+[.-1b], %edx
70#endif
71
72	andl	$0x8000, %ecx	// ECX == 0 iff X >= 0
73
74	fldt	MO(ln2_2)	// 0.5*ln2
75	xorl	%ecx, 12(%esp)
76	fldt	4(%esp)		// |x| : 0.5*ln2
77	fcoml	MO(half)	// |x| : 0.5*ln2
78	fld	%st(0)		// |x| : |x| : 0.5*ln2
79	fnstsw			// |x| : |x| : 0.5*ln2
80	sahf
81	jae	2f
82	fadd	%st, %st(1)	// |x| : 2*|x| : 0.5*ln2
83	fld	%st		// |x| : |x| : 2*|x| : 0.5*ln2
84	fsubrl	MO(one)		// 1-|x| : |x| : 2*|x| : 0.5*ln2
85	fxch			// |x| : 1-|x| : 2*|x| : 0.5*ln2
86	fmul	%st(2)		// 2*|x|^2 : 1-|x| : 2*|x| : 0.5*ln2
87	fdivp			// (2*|x|^2)/(1-|x|) : 2*|x| : 0.5*ln2
88	faddp			// 2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
89	fcoml	MO(limit)	// 2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
90	fnstsw			// 2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
91	sahf
92	jae	4f
93	fyl2xp1			// 0.5*ln2*ld(1+2*|x|+(2*|x|^2)/(1-|x|))
94	jecxz	3f
95	fchs			// 0.5*ln2*ld(1+2*x+(2*x^2)/(1-x))
963:	ret
97
98	.align ALIGNARG(4)
994:	faddl	MO(one)		// 1+2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
100	fyl2x			// 0.5*ln2*ld(1+2*|x|+(2*|x|^2)/(1-|x|))
101	jecxz	3f
102	fchs			// 0.5*ln2*ld(1+2*x+(2*x^2)/(1-x))
1033:	ret
104
105	.align ALIGNARG(4)
1062:	faddl	MO(one)		// 1+|x| : |x| : 0.5*ln2
107	fxch			// |x| : 1+|x| : 0.5*ln2
108	fsubrl	MO(one)		// 1-|x| : 1+|x| : 0.5*ln2
109	fdivrp			// (1+|x|)/(1-|x|) : 0.5*ln2
110	fyl2x			// 0.5*ln2*ld((1+|x|)/(1-|x|))
111	jecxz	3f
112	fchs			// 0.5*ln2*ld((1+x)/(1-x))
1133:	ret
114
115	// x == NaN or �Inf
1165:	cmpl	$0x80000000, 8(%esp)
117	ja	6f
118	cmpl	$0, 4(%esp)
119	je	7b
1206:	fldt	4(%esp)
121	ret
122END(__ieee754_atanhl)
123