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
42extern "C" {
43#endif
44
45extern __GNU_INLINE double
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
54extern __GNU_INLINE float
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
63extern __GNU_INLINE enum fp_class_type
64fp_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
116extern __GNU_INLINE enum fp_class_type
117fp_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
172extern __GNU_INLINE int
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 */
204extern __GNU_INLINE enum fp_precision_type
205__swapRP(enum fp_precision_type i)
206{
207	return (0);
208}
209
210extern __GNU_INLINE enum fp_direction_type
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
238extern __GNU_INLINE int
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
265extern __GNU_INLINE double
266sqrt(double d)
267{
268	return (__inline_sqrt(d));
269}
270
271extern __GNU_INLINE float
272sqrtf(float f)
273{
274	return (__inline_sqrtf(f));
275}
276
277extern __GNU_INLINE double
278fabs(double d)
279{
280	double ret;
281
282	__asm__ __volatile__("fabsd %1,%0\n\t" : "=e" (ret) : "e" (d));
283	return (ret);
284}
285
286extern __GNU_INLINE float
287fabsf(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