1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2011, Richard Lowe.
29 */
30
31 /* Functions in this file are duplicated in locallibm.il. Keep them in sync */
32
33 #ifndef _LIBM_INLINES_H
34 #define _LIBM_INLINES_H
35
36 #ifdef __GNUC__
37 #include <sys/types.h>
38 #include <sys/ieeefp.h>
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43
44 extern __GNU_INLINE double
45 __inline_sqrt(double d)
46 {
47 double ret;
48
49 __asm__ __volatile__("fsqrtd %1,%0\n\t" : "=e" (ret) : "e" (d));
50 return (ret);
51 }
52
53 extern __GNU_INLINE float
54 __inline_sqrtf(float f)
55 {
56 float ret;
57
58 __asm__ __volatile__("fsqrts %1,%0\n\t" : "=f" (ret) : "f" (f));
59 return (ret);
60 }
61
62 extern __GNU_INLINE enum fp_class_type
63 fp_classf(float f)
64 {
65 enum fp_class_type ret;
66 uint32_t tmp;
67
68 /* XXX: Separate input and output */
69 __asm__ __volatile__(
70 "sethi %%hi(0x80000000),%1\n\t"
71 "andncc %2,%1,%0\n\t"
72 "bne 1f\n\t"
73 "nop\n\t"
74 "mov 0,%0\n\t"
75 "ba 2f\n\t" /* x is 0 */
76 "nop\n\t"
77 "1:\n\t"
78 "sethi %%hi(0x7f800000),%1\n\t"
79 "andcc %0,%1,%%g0\n\t"
80 "bne 1f\n\t"
81 "nop\n\t"
82 "mov 1,%0\n\t"
83 "ba 2f\n\t" /* x is subnormal */
84 "nop\n\t"
85 "1:\n\t"
86 "cmp %0,%1\n\t"
87 "bge 1f\n\t"
88 "nop\n\t"
89 "mov 2,%0\n\t"
90 "ba 2f\n\t" /* x is normal */
91 "nop\n\t"
92 "1:\n\t"
93 "bg 1f\n\t"
94 "nop\n\t"
95 "mov 3,%0\n\t"
96 "ba 2f\n\t" /* x is __infinity */
97 "nop\n\t"
98 "1:\n\t"
99 "sethi %%hi(0x00400000),%1\n\t"
100 "andcc %0,%1,%%g0\n\t"
101 "mov 4,%0\n\t" /* x is quiet NaN */
102 "bne 2f\n\t"
103 "nop\n\t"
104 "mov 5,%0\n\t" /* x is signaling NaN */
105 "2:\n\t"
106 : "=r" (ret), "=&r" (tmp)
107 : "r" (f)
108 : "cc");
109 return (ret);
110 }
111
112 #define _HI_WORD(x) ((uint32_t *)&x)[0]
113 #define _LO_WORD(x) ((uint32_t *)&x)[1]
114
115 extern __GNU_INLINE enum fp_class_type
116 fp_class(double d)
117 {
118 enum fp_class_type ret;
119 uint32_t tmp;
120
121 __asm__ __volatile__(
122 "sethi %%hi(0x80000000),%1\n\t" /* %1 gets 80000000 */
123 "andn %2,%1,%0\n\t" /* %2-%0 gets abs(x) */
124 "orcc %0,%3,%%g0\n\t" /* set cc as x is zero/nonzero */
125 "bne 1f\n\t" /* branch if x is nonzero */
126 "nop\n\t"
127 "mov 0,%0\n\t"
128 "ba 2f\n\t" /* x is 0 */
129 "nop\n\t"
130 "1:\n\t"
131 "sethi %%hi(0x7ff00000),%1\n\t" /* %1 gets 7ff00000 */
132 "andcc %0,%1,%%g0\n\t" /* cc set by __exp field of x */
133 "bne 1f\n\t" /* branch if normal or max __exp */
134 "nop\n\t"
135 "mov 1,%0\n\t"
136 "ba 2f\n\t" /* x is subnormal */
137 "nop\n\t"
138 "1:\n\t"
139 "cmp %0,%1\n\t"
140 "bge 1f\n\t" /* branch if x is max __exp */
141 "nop\n\t"
142 "mov 2,%0\n\t"
143 "ba 2f\n\t" /* x is normal */
144 "nop\n\t"
145 "1:\n\t"
146 "andn %0,%1,%0\n\t" /* o0 gets msw __significand field */
147 "orcc %0,%3,%%g0\n\t" /* set cc by OR __significand */
148 "bne 1f\n\t" /* Branch if __nan */
149 "nop\n\t"
150 "mov 3,%0\n\t"
151 "ba 2f\n\t" /* x is __infinity */
152 "nop\n\t"
153 "1:\n\t"
154 "sethi %%hi(0x00080000),%1\n\t"
155 "andcc %0,%1,%%g0\n\t" /* set cc by quiet/sig bit */
156 "be 1f\n\t" /* Branch if signaling */
157 "nop\n\t"
158 "mov 4,%0\n\t" /* x is quiet NaN */
159 "ba 2f\n\t"
160 "nop\n\t"
161 "1:\n\t"
162 "mov 5,%0\n\t" /* x is signaling NaN */
163 "2:\n\t"
164 : "=&r" (ret), "=&r" (tmp)
165 : "r" (_HI_WORD(d)), "r" (_LO_WORD(d))
166 : "cc");
167
168 return (ret);
169 }
170
171 extern __GNU_INLINE int
172 __swapEX(int i)
173 {
174 int ret;
175 uint32_t fsr;
176 uint32_t tmp1, tmp2;
177
178 __asm__ __volatile__(
179 "and %4,0x1f,%2\n\t" /* tmp1 = %2 = %o1 */
180 "sll %2,5,%2\n\t" /* shift input to aexc bit location */
181 ".volatile\n\t"
182 "st %%fsr,%1\n\t"
183 "ld %1,%0\n\t" /* %0 = fsr */
184 "andn %0,0x3e0,%3\n\t" /* tmp2 = %3 = %o2 */
185 "or %2,%3,%2\n\t" /* %2 = new fsr */
186 "st %2,%1\n\t"
187 "ld %1,%%fsr\n\t"
188 "srl %0,5,%0\n\t"
189 "and %0,0x1f,%0\n\t" /* %0 = ret = %o0 */
190 ".nonvolatile\n\t"
191 : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2)
192 : "r" (i)
193 : "cc");
194
195 return (ret);
196 }
197
198 /*
199 * On the SPARC, __swapRP is a no-op; always return 0 for backward
200 * compatibility
201 */
202 /* ARGSUSED */
203 extern __GNU_INLINE enum fp_precision_type
204 __swapRP(enum fp_precision_type i)
205 {
206 return (0);
207 }
208
209 extern __GNU_INLINE enum fp_direction_type
210 __swapRD(enum fp_direction_type d)
211 {
212 enum fp_direction_type ret;
213 uint32_t fsr;
214 uint32_t tmp1, tmp2, tmp3;
215
216 __asm__ __volatile__(
217 "and %5,0x3,%0\n\t"
218 "sll %0,30,%2\n\t" /* shift input to RD bit location */
219 ".volatile\n\t"
220 "st %%fsr,%1\n\t"
221 "ld %1,%0\n\t" /* %0 = fsr */
222 "set 0xc0000000,%4\n\t" /* mask of rounding direction bits */
223 "andn %0,%4,%3\n\t"
224 "or %2,%3,%2\n\t" /* %2 = new fsr */
225 "st %2,%1\n\t"
226 "ld %1,%%fsr\n\t"
227 "srl %0,30,%0\n\t"
228 "and %0,0x3,%0\n\t"
229 ".nonvolatile\n\t"
230 : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)
231 : "r" (d)
232 : "cc");
233
234 return (ret);
235 }
236
237 extern __GNU_INLINE int
238 __swapTE(int i)
239 {
240 int ret;
241 uint32_t fsr, tmp1, tmp2;
242
243 __asm__ __volatile__(
244 "and %4,0x1f,%0\n\t"
245 "sll %0,23,%2\n\t" /* shift input to TEM bit location */
246 ".volatile\n\t"
247 "st %%fsr,%1\n\t"
248 "ld %1,%0\n\t" /* %0 = fsr */
249 "set 0x0f800000,%3\n\t" /* mask of TEM (Trap Enable Mode bits) */
250 "andn %0,%3,%3\n\t"
251 "or %2,%3,%2\n\t" /* %2 = new fsr */
252 "st %2,%1\n\t"
253 "ld %1,%%fsr\n\t"
254 "srl %0,23,%0\n\t"
255 "and %0,0x1f,%0\n\t"
256 ".nonvolatile\n\t"
257 : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2)
258 : "r" (i)
259 : "cc");
260
261 return (ret);
262 }
263
264 extern __GNU_INLINE double
265 sqrt(double d)
266 {
267 return (__inline_sqrt(d));
268 }
269
270 extern __GNU_INLINE float
271 sqrtf(float f)
272 {
273 return (__inline_sqrtf(f));
274 }
275
276 extern __GNU_INLINE double
277 fabs(double d)
278 {
279 double ret;
280
281 __asm__ __volatile__("fabsd %1,%0\n\t" : "=e" (ret) : "e" (d));
282 return (ret);
283 }
284
285 extern __GNU_INLINE float
286 fabsf(float f)
287 {
288 float ret;
289
290 __asm__ __volatile__("fabss %1,%0\n\t" : "=f" (ret) : "f" (f));
291 return (ret);
292 }
293
294 #ifdef __cplusplus
295 }
296 #endif
297 #endif /* __GNUC */
298 #endif /* _LIBM_INLINES_H */