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