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 
38 #include <sys/types.h>
39 #include <sys/ieeefp.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 extern __GNU_INLINE double
__inline_sqrt(double d)46 __inline_sqrt(double d)
47 {
48 	double ret;
49 
50 	__asm__ __volatile__("fsqrtd %1,%0\n\t" : "=e" (ret) : "e" (d));
51 	return (ret);
52 }
53 
54 extern __GNU_INLINE float
__inline_sqrtf(float f)55 __inline_sqrtf(float f)
56 {
57 	float ret;
58 
59 	__asm__ __volatile__("fsqrts %1,%0\n\t" : "=f" (ret) : "f" (f));
60 	return (ret);
61 }
62 
63 extern __GNU_INLINE enum fp_class_type
fp_classf(float f)64 fp_classf(float f)
65 {
66 	enum fp_class_type ret;
67 	uint32_t tmp;
68 
69 	/* XXX: Separate input and output */
70 	__asm__ __volatile__(
71 	    "sethi  %%hi(0x80000000),%1\n\t"
72 	    "andncc %2,%1,%0\n\t"
73 	    "bne    1f\n\t"
74 	    "nop\n\t"
75 	    "mov    0,%0\n\t"
76 	    "ba	2f\n\t"		/* x is 0 */
77 	    "nop\n\t"
78 	    "1:\n\t"
79 	    "sethi  %%hi(0x7f800000),%1\n\t"
80 	    "andcc  %0,%1,%%g0\n\t"
81 	    "bne    1f\n\t"
82 	    "nop\n\t"
83 	    "mov    1,%0\n\t"
84 	    "ba	    2f\n\t"	/* x is subnormal */
85 	    "nop\n\t"
86 	    "1:\n\t"
87 	    "cmp    %0,%1\n\t"
88 	    "bge    1f\n\t"
89 	    "nop\n\t"
90 	    "mov    2,%0\n\t"
91 	    "ba	    2f\n\t"	/* x is normal */
92 	    "nop\n\t"
93 	    "1:\n\t"
94 	    "bg	    1f\n\t"
95 	    "nop\n\t"
96 	    "mov    3,%0\n\t"
97 	    "ba	    2f\n\t"	/* x is __infinity */
98 	    "nop\n\t"
99 	    "1:\n\t"
100 	    "sethi  %%hi(0x00400000),%1\n\t"
101 	    "andcc  %0,%1,%%g0\n\t"
102 	    "mov    4,%0\n\t"	/* x is quiet NaN */
103 	    "bne    2f\n\t"
104 	    "nop\n\t"
105 	    "mov    5,%0\n\t"	/* x is signaling NaN */
106 	    "2:\n\t"
107 	    : "=r" (ret), "=&r" (tmp)
108 	    : "r" (f)
109 	    : "cc");
110 	return (ret);
111 }
112 
113 #define	_HI_WORD(x)	((uint32_t *)&x)[0]
114 #define	_LO_WORD(x)	((uint32_t *)&x)[1]
115 
116 extern __GNU_INLINE enum fp_class_type
fp_class(double d)117 fp_class(double d)
118 {
119 	enum fp_class_type ret;
120 	uint32_t tmp;
121 
122 	__asm__ __volatile__(
123 	    "sethi %%hi(0x80000000),%1\n\t"	/* %1 gets 80000000 */
124 	    "andn  %2,%1,%0\n\t"		/* %2-%0 gets abs(x) */
125 	    "orcc  %0,%3,%%g0\n\t"		/* set cc as x is zero/nonzero */
126 	    "bne   1f\n\t"			/* branch if x is nonzero */
127 	    "nop\n\t"
128 	    "mov   0,%0\n\t"
129 	    "ba	   2f\n\t"			/* x is 0 */
130 	    "nop\n\t"
131 	    "1:\n\t"
132 	    "sethi %%hi(0x7ff00000),%1\n\t"	/* %1 gets 7ff00000 */
133 	    "andcc %0,%1,%%g0\n\t"		/* cc set by __exp field of x */
134 	    "bne   1f\n\t"			/* branch if normal or max __exp */
135 	    "nop\n\t"
136 	    "mov   1,%0\n\t"
137 	    "ba	   2f\n\t"			/* x is subnormal */
138 	    "nop\n\t"
139 	    "1:\n\t"
140 	    "cmp   %0,%1\n\t"
141 	    "bge   1f\n\t"			/* branch if x is max __exp */
142 	    "nop\n\t"
143 	    "mov   2,%0\n\t"
144 	    "ba	   2f\n\t"			/* x is normal */
145 	    "nop\n\t"
146 	    "1:\n\t"
147 	    "andn  %0,%1,%0\n\t"		/* o0 gets msw __significand field */
148 	    "orcc  %0,%3,%%g0\n\t"		/* set cc by OR __significand */
149 	    "bne   1f\n\t"			/* Branch if __nan */
150 	    "nop\n\t"
151 	    "mov   3,%0\n\t"
152 	    "ba	   2f\n\t"			/* x is __infinity */
153 	    "nop\n\t"
154 	    "1:\n\t"
155 	    "sethi %%hi(0x00080000),%1\n\t"
156 	    "andcc %0,%1,%%g0\n\t"		/* set cc by quiet/sig bit */
157 	    "be	   1f\n\t"			/* Branch if signaling */
158 	    "nop\n\t"
159 	    "mov   4,%0\n\t"			/* x is quiet NaN */
160 	    "ba	   2f\n\t"
161 	    "nop\n\t"
162 	    "1:\n\t"
163 	    "mov   5,%0\n\t"			/* x is signaling NaN */
164 	    "2:\n\t"
165 	    : "=&r" (ret), "=&r" (tmp)
166 	    : "r" (_HI_WORD(d)), "r" (_LO_WORD(d))
167 	    : "cc");
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 	__asm__ __volatile__(
245 	    "and  %4,0x1f,%0\n\t"
246 	    "sll  %0,23,%2\n\t"		/* shift input to TEM bit location */
247 	    ".volatile\n\t"
248 	    "st   %%fsr,%1\n\t"
249 	    "ld	  %1,%0\n\t"		/* %0 = fsr */
250 	    "set  0x0f800000,%3\n\t"	/* mask of TEM (Trap Enable Mode bits) */
251 	    "andn %0,%3,%3\n\t"
252 	    "or   %2,%3,%2\n\t"		/* %2 = new fsr */
253 	    "st	  %2,%1\n\t"
254 	    "ld	  %1,%%fsr\n\t"
255 	    "srl  %0,23,%0\n\t"
256 	    "and  %0,0x1f,%0\n\t"
257 	    ".nonvolatile\n\t"
258 	    : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2)
259 	    : "r" (i)
260 	    : "cc");
261 
262 	return (ret);
263 }
264 
265 extern __GNU_INLINE double
sqrt(double d)266 sqrt(double d)
267 {
268 	return (__inline_sqrt(d));
269 }
270 
271 extern __GNU_INLINE float
sqrtf(float f)272 sqrtf(float f)
273 {
274 	return (__inline_sqrtf(f));
275 }
276 
277 extern __GNU_INLINE double
fabs(double d)278 fabs(double d)
279 {
280 	double ret;
281 
282 	__asm__ __volatile__("fabsd %1,%0\n\t" : "=e" (ret) : "e" (d));
283 	return (ret);
284 }
285 
286 extern __GNU_INLINE float
fabsf(float f)287 fabsf(float f)
288 {
289 	float ret;
290 
291 	__asm__ __volatile__("fabss %1,%0\n\t" : "=f" (ret) : "f" (f));
292 	return (ret);
293 }
294 
295 #ifdef __cplusplus
296 }
297 #endif
298 
299 #endif	/* __GNUC */
300 
301 #endif /* _LIBM_INLINES_H */
302