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 #ifndef _LIBM_INLINES_H
32 #define _LIBM_INLINES_H
33
34 #ifdef __GNUC__
35
36 #include <sys/types.h>
37 #include <sys/ieeefp.h>
38
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42
43 extern __GNU_INLINE double
__inline_sqrt(double d)44 __inline_sqrt(double d)
45 {
46 double ret;
47
48 __asm__ __volatile__("fsqrtd %1,%0\n\t" : "=e" (ret) : "e" (d));
49 return (ret);
50 }
51
52 extern __GNU_INLINE float
__inline_sqrtf(float f)53 __inline_sqrtf(float f)
54 {
55 float ret;
56
57 __asm__ __volatile__("fsqrts %1,%0\n\t" : "=f" (ret) : "f" (f));
58 return (ret);
59 }
60
61 extern __GNU_INLINE enum fp_class_type
fp_classf(float f)62 fp_classf(float f)
63 {
64 enum fp_class_type ret;
65 uint32_t tmp;
66
67 /* XXX: Separate input and output */
68 __asm__ __volatile__(
69 "sethi %%hi(0x80000000),%1\n\t"
70 "andncc %2,%1,%0\n\t"
71 "bne 1f\n\t"
72 "nop\n\t"
73 "mov 0,%0\n\t"
74 "ba 2f\n\t" /* x is 0 */
75 "nop\n\t"
76 "1:\n\t"
77 "sethi %%hi(0x7f800000),%1\n\t"
78 "andcc %0,%1,%%g0\n\t"
79 "bne 1f\n\t"
80 "nop\n\t"
81 "mov 1,%0\n\t"
82 "ba 2f\n\t" /* x is subnormal */
83 "nop\n\t"
84 "1:\n\t"
85 "cmp %0,%1\n\t"
86 "bge 1f\n\t"
87 "nop\n\t"
88 "mov 2,%0\n\t"
89 "ba 2f\n\t" /* x is normal */
90 "nop\n\t"
91 "1:\n\t"
92 "bg 1f\n\t"
93 "nop\n\t"
94 "mov 3,%0\n\t"
95 "ba 2f\n\t" /* x is __infinity */
96 "nop\n\t"
97 "1:\n\t"
98 "sethi %%hi(0x00400000),%1\n\t"
99 "andcc %0,%1,%%g0\n\t"
100 "mov 4,%0\n\t" /* x is quiet NaN */
101 "bne 2f\n\t"
102 "nop\n\t"
103 "mov 5,%0\n\t" /* x is signaling NaN */
104 "2:\n\t"
105 : "=r" (ret), "=&r" (tmp)
106 : "r" (f)
107 : "cc");
108 return (ret);
109 }
110
111 #define _HI_WORD(x) ((uint32_t *)&x)[0]
112 #define _LO_WORD(x) ((uint32_t *)&x)[1]
113
114 extern __GNU_INLINE enum fp_class_type
fp_class(double d)115 fp_class(double d)
116 {
117 enum fp_class_type ret;
118 uint32_t tmp;
119
120 /* BEGIN CSTYLED */
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 /* END CSTYLED */
168
169 return (ret);
170 }
171
172 extern __GNU_INLINE int
__swapEX(int i)173 __swapEX(int i)
174 {
175 int ret;
176 uint32_t fsr;
177 uint32_t tmp1, tmp2;
178
179 __asm__ __volatile__(
180 "and %4,0x1f,%2\n\t" /* tmp1 = %2 = %o1 */
181 "sll %2,5,%2\n\t" /* shift input to aexc bit location */
182 ".volatile\n\t"
183 "st %%fsr,%1\n\t"
184 "ld %1,%0\n\t" /* %0 = fsr */
185 "andn %0,0x3e0,%3\n\t" /* tmp2 = %3 = %o2 */
186 "or %2,%3,%2\n\t" /* %2 = new fsr */
187 "st %2,%1\n\t"
188 "ld %1,%%fsr\n\t"
189 "srl %0,5,%0\n\t"
190 "and %0,0x1f,%0\n\t" /* %0 = ret = %o0 */
191 ".nonvolatile\n\t"
192 : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2)
193 : "r" (i)
194 : "cc");
195
196 return (ret);
197 }
198
199 /*
200 * On the SPARC, __swapRP is a no-op; always return 0 for backward
201 * compatibility
202 */
203 /* ARGSUSED */
204 extern __GNU_INLINE enum fp_precision_type
__swapRP(enum fp_precision_type i)205 __swapRP(enum fp_precision_type i)
206 {
207 return (0);
208 }
209
210 extern __GNU_INLINE enum fp_direction_type
__swapRD(enum fp_direction_type d)211 __swapRD(enum fp_direction_type d)
212 {
213 enum fp_direction_type ret;
214 uint32_t fsr;
215 uint32_t tmp1, tmp2, tmp3;
216
217 __asm__ __volatile__(
218 "and %5,0x3,%0\n\t"
219 "sll %0,30,%2\n\t" /* shift input to RD bit location */
220 ".volatile\n\t"
221 "st %%fsr,%1\n\t"
222 "ld %1,%0\n\t" /* %0 = fsr */
223 "set 0xc0000000,%4\n\t" /* mask of rounding direction bits */
224 "andn %0,%4,%3\n\t"
225 "or %2,%3,%2\n\t" /* %2 = new fsr */
226 "st %2,%1\n\t"
227 "ld %1,%%fsr\n\t"
228 "srl %0,30,%0\n\t"
229 "and %0,0x3,%0\n\t"
230 ".nonvolatile\n\t"
231 : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)
232 : "r" (d)
233 : "cc");
234
235 return (ret);
236 }
237
238 extern __GNU_INLINE int
__swapTE(int i)239 __swapTE(int i)
240 {
241 int ret;
242 uint32_t fsr, tmp1, tmp2;
243
244 /* BEGIN CSTYLED */
245 __asm__ __volatile__(
246 "and %4,0x1f,%0\n\t"
247 "sll %0,23,%2\n\t" /* shift input to TEM bit location */
248 ".volatile\n\t"
249 "st %%fsr,%1\n\t"
250 "ld %1,%0\n\t" /* %0 = fsr */
251 "set 0x0f800000,%3\n\t" /* mask of TEM (Trap Enable Mode bits) */
252 "andn %0,%3,%3\n\t"
253 "or %2,%3,%2\n\t" /* %2 = new fsr */
254 "st %2,%1\n\t"
255 "ld %1,%%fsr\n\t"
256 "srl %0,23,%0\n\t"
257 "and %0,0x1f,%0\n\t"
258 ".nonvolatile\n\t"
259 : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2)
260 : "r" (i)
261 : "cc");
262 /* END CSTYLED */
263
264 return (ret);
265 }
266
267 extern __GNU_INLINE double
sqrt(double d)268 sqrt(double d)
269 {
270 return (__inline_sqrt(d));
271 }
272
273 extern __GNU_INLINE float
sqrtf(float f)274 sqrtf(float f)
275 {
276 return (__inline_sqrtf(f));
277 }
278
279 extern __GNU_INLINE double
fabs(double d)280 fabs(double d)
281 {
282 double ret;
283
284 __asm__ __volatile__("fabsd %1,%0\n\t" : "=e" (ret) : "e" (d));
285 return (ret);
286 }
287
288 extern __GNU_INLINE float
fabsf(float f)289 fabsf(float f)
290 {
291 float ret;
292
293 __asm__ __volatile__("fabss %1,%0\n\t" : "=f" (ret) : "f" (f));
294 return (ret);
295 }
296
297 #ifdef __cplusplus
298 }
299 #endif
300
301 #endif /* __GNUC */
302
303 #endif /* _LIBM_INLINES_H */
304