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 libm.m4. Keep them in sync */
32
33 #ifndef _LIBM_INLINES_H
34 #define _LIBM_INLINES_H
35
36 #ifdef __GNUC__
37
38 #include <sys/types.h>
39 #include <sys/ieeefp.h>
40
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44
45 extern __inline__ double
46 __inline_sqrt(double d)
47 {
48 double ret;
49
50 __asm__ __volatile__("fsqrtd %0,%0\n\t" : "=e" (ret) : "0" (d));
51 return (ret);
52 }
53
54 extern __inline__ float
55 __inline_sqrtf(float f)
56 {
57 float ret;
58
59 __asm__ __volatile__("fsqrts %0,%0\n\t" : "=f" (ret) : "0" (f));
60 return (ret);
61 }
62
63 extern __inline__ enum fp_class_type
64 fp_classf(float f)
65 {
66 enum fp_class_type ret;
67
68 __asm__ __volatile__(
69 "sethi %%hi(0x80000000),%%o2\n\t"
70 "andncc %0,%%o2,%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),%%o2\n\t"
78 "andcc %0,%%o2,%%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,%%o2\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),%%o2\n\t"
99 "andcc %0,%%o2,%%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)
106 : "0" (f)
107 : "o2");
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 __inline__ enum fp_class_type
115 fp_class(double d)
116 {
117 enum fp_class_type ret;
118
119 __asm__ __volatile__(
120 "sethi %%hi(0x80000000),%%o2\n\t" /* o2 gets 80000000 */
121 "andn %0,%%o2,%0\n\t" /* o0-o1 gets abs(x) */
122 "orcc %0,%2,%%g0\n\t" /* set cc as x is zero/nonzero */
123 "bne 1f\n\t" /* branch if x is nonzero */
124 "nop\n\t"
125 "mov 0,%0\n\t"
126 "ba 2f\n\t" /* x is 0 */
127 "nop\n\t"
128 "1:\n\t"
129 "sethi %%hi(0x7ff00000),%%o2\n\t" /* o2 gets 7ff00000 */
130 "andcc %0,%%o2,%%g0\n\t" /* cc set by __exp field of x */
131 "bne 1f\n\t" /* branch if normal or max __exp */
132 "nop\n\t"
133 "mov 1,%0\n\t"
134 "ba 2f\n\t" /* x is subnormal */
135 "nop\n\t"
136 "1:\n\t"
137 "cmp %0,%%o2\n\t"
138 "bge 1f\n\t" /* branch if x is max __exp */
139 "nop\n\t"
140 "mov 2,%0\n\t"
141 "ba 2f\n\t" /* x is normal */
142 "nop\n\t"
143 "1:\n\t"
144 "andn %0,%%o2,%0\n\t" /* o0 gets msw __significand field */
145 "orcc %0,%2,%%g0\n\t" /* set cc by OR __significand */
146 "bne 1f\n\t" /* Branch if __nan */
147 "nop\n\t"
148 "mov 3,%0\n\t"
149 "ba 2f\n\t" /* x is __infinity */
150 "nop\n\t"
151 "1:\n\t"
152 "sethi %%hi(0x00080000),%%o2\n\t"
153 "andcc %0,%%o2,%%g0\n\t" /* set cc by quiet/sig bit */
154 "be 1f\n\t" /* Branch if signaling */
155 "nop\n\t"
156 "mov 4,%0\n\t" /* x is quiet NaN */
157 "ba 2f\n\t"
158 "nop\n\t"
159 "1:\n\t"
160 "mov 5,%0\n\t" /* x is signaling NaN */
161 "2:\n\t"
162 : "=r" (ret)
163 : "0" (_HI_WORD(d)), "r" (_LO_WORD(d))
164 : "o2");
165
166 return (ret);
167 }
168
169 extern __inline__ int
170 __swapEX(int i)
171 {
172 int ret;
173 uint32_t fsr;
174
175 __asm__ __volatile__(
176 "and %0,0x1f,%%o1\n\t"
177 "sll %%o1,5,%%o1\n\t" /* input to aexc bit location */
178 ".volatile\n\t"
179 "st %%fsr,%2\n\t"
180 "ld %2,%0\n\t" /* = fsr */
181 "andn %0,0x3e0,%%o2\n\t"
182 "or %%o1,%%o2,%%o1\n\t" /* o1 = new fsr */
183 "st %%o1,%2\n\t"
184 "ld %2,%%fsr\n\t"
185 "srl %0,5,%0\n\t"
186 "and %0,0x1f,%0\n\t"
187 ".nonvolatile\n\t"
188 : "=r" (ret)
189 : "0" (i), "m" (fsr)
190 : "o1", "o2");
191
192 return (ret);
193 }
194
195 /*
196 * On the SPARC, __swapRP is a no-op; always return 0 for backward
197 * compatibility
198 */
199 /* ARGSUSED */
200 extern __inline__ enum fp_precision_type
201 __swapRP(enum fp_precision_type i)
202 {
203 return (0);
204 }
205
206 extern __inline__ enum fp_direction_type
207 __swapRD(enum fp_direction_type d)
208 {
209 enum fp_direction_type ret;
210 uint32_t fsr;
211
212 __asm__ __volatile__(
213 "and %0,0x3,%0\n\t"
214 "sll %0,30,%%o1\n\t" /* input to RD bit location */
215 ".volatile\n\t"
216 "st %%fsr,%2\n\t"
217 "ld %2,%0\n\t" /* o0 = fsr */
218 "set 0xc0000000,%%o4\n\t" /* mask of rounding direction bits */
219 "andn %0,%%o4,%%o2\n\t"
220 "or %%o1,%%o2,%%o1\n\t" /* o1 = new fsr */
221 "st %%o1,%2\n\t"
222 "ld %2,%%fsr\n\t"
223 "srl %0,30,%0\n\t"
224 "and %0,0x3,%0\n\t"
225 ".nonvolatile\n\t"
226 : "=r" (ret)
227 : "0" (d), "m" (fsr)
228 : "o1", "o2", "o4");
229
230 return (ret);
231 }
232
233 extern __inline__ int
234 __swapTE(int i)
235 {
236 int ret;
237 uint32_t fsr;
238
239 __asm__ __volatile__(
240 "and %0,0x1f,%0\n\t"
241 "sll %0,23,%%o1\n\t" /* input to TEM bit location */
242 ".volatile\n\t"
243 "st %%fsr,%2\n\t"
244 "ld %2,%0\n\t" /* o0 = fsr */
245 "set 0x0f800000,%%o4\n\t" /* mask of TEM (Trap Enable Mode bits) */
246 "andn %0,%%o4,%%o2\n\t"
247 "or %%o1,%%o2,%%o1\n\t" /* o1 = new fsr */
248 "st %%o1,%2\n\t"
249 "ld %2,%%fsr\n\t"
250 "srl %0,23,%0\n\t"
251 "and %0,0x1f,%0\n\t"
252 ".nonvolatile\n\t"
253 : "=r" (ret)
254 : "0" (i), "m" (fsr)
255 : "o1", "o2", "o4");
256
257 return (ret);
258 }
259
260 extern __inline__ double
261 sqrt(double d)
262 {
263 double ret;
264
265 __asm__ __volatile__("fsqrtd %0,%0\n\t" : "=f" (ret) : "0" (d));
266 return (ret);
267 }
268
269 extern __inline__ float
270 sqrtf(float f)
271 {
272 float ret;
273
274 __asm__ __volatile__("fsqrts %0,%0\n\t" : "=f" (ret) : "0" (f));
275 return (ret);
276 }
277
278 extern __inline__ double
279 fabs(double d)
280 {
281 double ret;
282
283 __asm__ __volatile__("fabsd %0,%0\n\t" : "=e" (ret) : "0" (d));
284 return (ret);
285 }
286
287 extern __inline__ float
288 fabsf(float f)
289 {
290 float ret;
291
292 __asm__ __volatile__("fabss %0,%0\n\t" : "=f" (ret) : "0" (f));
293 return (ret);
294 }
295
296 #ifdef __cplusplus
297 }
298 #endif
299
300 #endif /* __GNUC */
301
302 #endif /* _LIBM_INLINES_H */