1/* ix87 specific implementation of arctanh function.
2   Copyright (C) 1996-2022 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, see
17   <https://www.gnu.org/licenses/>.  */
18
19#include <machine/asm.h>
20#include <libm-alias-finite.h>
21
22	.section .rodata
23
24	.align ALIGNARG(4)
25	/* Please note that we use double values for 0.5 and 1.0.  These
26	   numbers have exact representations and so we don't get accuracy
27	   problems.  The advantage is that the code is simpler.  */
28	.type half,@object
29half:	.double 0.5
30	ASM_SIZE_DIRECTIVE(half)
31	.type one,@object
32one:	.double 1.0
33	ASM_SIZE_DIRECTIVE(one)
34	/* It is not important that this constant is precise.  It is only
35	   a value which is known to be on the safe side for using the
36	   fyl2xp1 instruction.  */
37	.type limit,@object
38limit:	.double 0.29
39	ASM_SIZE_DIRECTIVE(limit)
40	.align ALIGNARG(4)
41	.type ln2_2,@object
42ln2_2:	.tfloat 0.3465735902799726547086160
43	ASM_SIZE_DIRECTIVE(ln2_2)
44
45#ifdef PIC
46#define MO(op) op##@GOTOFF(%edx)
47#else
48#define MO(op) op
49#endif
50
51	.text
52ENTRY(__ieee754_atanhl)
53	movl	12(%esp), %ecx
54
55	movl	%ecx, %eax
56	andl	$0x7fff, %eax
57	cmpl	$0x7fff, %eax
58	je	5f
59	cmpl	$0x3fdf, %eax
60	jge	7f
61	// Exponent below -32; return x, with underflow if subnormal.
62	fldt	4(%esp)
63	cmpl	$0, %eax
64	jne	8f
65	fld	%st(0)
66	fmul	%st(0)
67	fstp	%st(0)
688:	ret
697:
70
71#ifdef PIC
72	LOAD_PIC_REG (dx)
73#endif
74
75	andl	$0x8000, %ecx	// ECX == 0 iff X >= 0
76
77	fldt	MO(ln2_2)	// 0.5*ln2
78	xorl	%ecx, 12(%esp)
79	fldt	4(%esp)		// |x| : 0.5*ln2
80	fcoml	MO(half)	// |x| : 0.5*ln2
81	fld	%st(0)		// |x| : |x| : 0.5*ln2
82	fnstsw			// |x| : |x| : 0.5*ln2
83	sahf
84	jae	2f
85	fadd	%st, %st(1)	// |x| : 2*|x| : 0.5*ln2
86	fld	%st		// |x| : |x| : 2*|x| : 0.5*ln2
87	fsubrl	MO(one)		// 1-|x| : |x| : 2*|x| : 0.5*ln2
88	fxch			// |x| : 1-|x| : 2*|x| : 0.5*ln2
89	fmul	%st(2)		// 2*|x|^2 : 1-|x| : 2*|x| : 0.5*ln2
90	fdivp			// (2*|x|^2)/(1-|x|) : 2*|x| : 0.5*ln2
91	faddp			// 2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
92	fcoml	MO(limit)	// 2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
93	fnstsw			// 2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
94	sahf
95	jae	4f
96	fyl2xp1			// 0.5*ln2*ld(1+2*|x|+(2*|x|^2)/(1-|x|))
97	jecxz	3f
98	fchs			// 0.5*ln2*ld(1+2*x+(2*x^2)/(1-x))
993:	ret
100
101	.align ALIGNARG(4)
1024:	faddl	MO(one)		// 1+2*|x|+(2*|x|^2)/(1-|x|) : 0.5*ln2
103	fyl2x			// 0.5*ln2*ld(1+2*|x|+(2*|x|^2)/(1-|x|))
104	jecxz	3f
105	fchs			// 0.5*ln2*ld(1+2*x+(2*x^2)/(1-x))
1063:	ret
107
108	.align ALIGNARG(4)
1092:	faddl	MO(one)		// 1+|x| : |x| : 0.5*ln2
110	fxch			// |x| : 1+|x| : 0.5*ln2
111	fsubrl	MO(one)		// 1-|x| : 1+|x| : 0.5*ln2
112	fdivrp			// (1+|x|)/(1-|x|) : 0.5*ln2
113	fyl2x			// 0.5*ln2*ld((1+|x|)/(1-|x|))
114	jecxz	3f
115	fchs			// 0.5*ln2*ld((1+x)/(1-x))
1163:	ret
117
118	// x == NaN or �Inf
1195:	cmpl	$0x80000000, 8(%esp)
120	ja	6f
121	cmpl	$0, 4(%esp)
122	je	7b
1236:	fldt	4(%esp)
124	fadd	%st(0)
125	ret
126END(__ieee754_atanhl)
127libm_alias_finite (__ieee754_atanhl, __atanhl)
128