Fix i386 asinhl (sNaN) (bug 20218).
[glibc.git] / sysdeps / i386 / fpu / s_asinhl.S
blobe055386071b9e67236e16054f081f486592e1d31
1 /* ix87 specific implementation of arcsinh.
2    Copyright (C) 1996-2016 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
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.
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.
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
20 #include <machine/asm.h>
22         .section .rodata
24         .align ALIGNARG(4)
25         .type huge,@object
26 huge:   .tfloat 1e+4930
27         ASM_SIZE_DIRECTIVE(huge)
28         .align ALIGNARG(4)
29         /* Please note that we use double value for 1.0.  This number
30            has an exact representation and so we don't get accuracy
31            problems.  The advantage is that the code is simpler.  */
32         .type one,@object
33 one:    .double 1.0
34         ASM_SIZE_DIRECTIVE(one)
35         /* It is not important that this constant is precise.  It is only
36            a value which is known to be on the safe side for using the
37            fyl2xp1 instruction.  */
38         .type limit,@object
39 limit:  .double 0.29
40         ASM_SIZE_DIRECTIVE(limit)
42 #ifdef PIC
43 #define MO(op) op##@GOTOFF(%edx)
44 #else
45 #define MO(op) op
46 #endif
48         .text
49 ENTRY(__asinhl)
50         movl    12(%esp), %ecx
51         movl    $0x7fff, %eax
52         andl    %ecx, %eax
53         andl    $0x8000, %ecx
54         movl    %eax, %edx
55         orl     $0xffff8000, %edx
56         incl    %edx
57         jz      7f                      // x in ±Inf or NaN
58         xorl    %ecx, 12(%esp)
59         fldt    4(%esp)                 // |x|
60         cmpl    $0x3fde, %eax
61         jb      2f                      // |x| < 2^-34
62         fldln2                          // log(2) : |x|
63         cmpl    $0x4020, %eax
64         fxch                            // |x| : log(2)
65         ja      3f                      // |x| > 2^34
66 #ifdef  PIC
67         LOAD_PIC_REG (dx)
68 #endif
69         cmpl    $0x4000, %eax
70         ja      5f                      // |x| > 2
72         // 2^-34 <= |x| <= 2 => y = sign(x)*log1p(|x|+|x|^2/(1+sqrt(1+|x|^2)))
73         fld     %st                     // |x| : |x| : log(2)
74         fmul    %st(1)                  // |x|^2 : |x| : log(2)
75         fld     %st                     // |x|^2 : |x|^2 : |x| : log(2)
76         faddl   MO(one)                 // 1+|x|^2 : |x|^2 : |x| : log(2)
77         fsqrt                           // sqrt(1+|x|^2) : |x|^2 : |x| : log(2)
78         faddl   MO(one)                 // 1+sqrt(1+|x|^2) : |x|^2 : |x| : log(2)
79         fdivrp                          // |x|^2/(1+sqrt(1+|x|^2)) : |x| : log(2)
80         faddp                           // |x|+|x|^2/(1+sqrt(1+|x|^2)) : log(2)
81         fcoml   MO(limit)
82         fnstsw
83         sahf
84         ja      6f
85         fyl2xp1
86         jecxz   4f
87         fchs
88 4:      ret
90 7:      fldt    4(%esp)
91         fadd    %st
92         ret
94 6:      faddl   MO(one)
95         fyl2x
96         jecxz   4f
97         fchs
98 4:      ret
100         // |x| < 2^-34 => y = x (inexact iff |x| != 0.0)
101         .align ALIGNARG(4)
103 #ifdef  PIC
104         LOAD_PIC_REG (dx)
105 #endif
106         jecxz   4f
107         fchs                            // x
108 4:      fld     %st                     // x : x
109         fldt    MO(huge)                // huge : x : x
110         faddp                           // huge+x : x
111         fstp    %st(0)                  // x
112         cmpl    $0x0001, %eax
113         jae     8f
114         fld     %st(0)
115         fmul    %st(0)
116         fstp    %st(0)
117 8:      ret
119         // |x| > 2^34 => y = sign(x) * (log(|x|) + log(2))
120         .align ALIGNARG(4)
121 3:      fyl2x                           // log(|x|)
122         fldln2                          // log(2) : log(|x|)
123         faddp                           // log(|x|)+log(2)
124         jecxz   4f
125         fchs
126 4:      ret
128         // |x| > 2 => y = sign(x) * log(2*|x| + 1/(|x|+sqrt(x*x+1)))
129         .align ALIGNARG(4)
130 5:      fld     %st                     // |x| : |x| : log(2)
131         fadd    %st, %st(1)             // |x| : 2*|x| : log(2)
132         fld     %st                     // |x| : |x| : 2*|x| : log(2)
133         fmul    %st(1)                  // |x|^2 : |x| : 2*|x| : log(2)
134         faddl   MO(one)                 // 1+|x|^2 : |x| : 2*|x| : log(2)
135         fsqrt                           // sqrt(1+|x|^2) : |x| : 2*|x| : log(2)
136         faddp                           // |x|+sqrt(1+|x|^2) : 2*|x| : log(2)
137         fdivrl  MO(one)                 // 1/(|x|+sqrt(1+|x|^2)) : 2*|x| : log(2)
138         faddp                           // 2*|x|+1/(|x|+sqrt(1+|x|^2)) : log(2)
139         fyl2x                           // log(2*|x|+1/(|x|+sqrt(1+|x|^2)))
140         jecxz   4f
141         fchs
142 4:      ret
143 END(__asinhl)
144 weak_alias (__asinhl, asinhl)