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 enum fp_class_type
46fp_classf(float f)
47{
48	enum fp_class_type ret;
49	int fint;		/* scratch for f as int */
50	uint64_t tmp;
51
52	__asm__ __volatile__(
53	    "fabss  %3,%3\n\t"
54	    "st	    %3,%1\n\t"
55	    "ld	    %1,%0\n\t"
56	    "orcc   %%g0,%0,%%g0\n\t"
57	    "be,pn  %%icc,2f\n\t"
58	    "nop\n\t"
59	    "1:\n\t"
60	    "sethi  %%hi(0x7f800000),%2\n\t"
61	    "andcc  %0,%2,%%g0\n\t"
62	    "bne,pt %%icc,1f\n\t"
63	    "nop\n\t"
64	    "or	    %%g0,1,%0\n\t"
65	    "ba	    2f\n\t"	/* subnormal */
66	    "nop\n\t"
67	    "1:\n\t"
68	    "subcc  %0,%2,%%g0\n\t"
69	    "bge,pn %%icc,1f\n\t"
70	    "nop\n\t"
71	    "or	    %%g0,2,%0\n\t"
72	    "ba	    2f\n\t"	/* normal */
73	    "nop\n\t"
74	    "1:\n\t"
75	    "bg,pn  %%icc,1f\n\t"
76	    "nop\n\t"
77	    "or	    %%g0,3,%0\n\t"
78	    "ba	    2f\n\t"	/* infinity */
79	    "nop\n\t"
80	    "1:\n\t"
81	    "sethi  %%hi(0x00400000),%2\n\t"
82	    "andcc  %0,%2,%%g0\n\t"
83	    "or	    %%g0,4,%0\n\t"
84	    "bne,pt %%icc,2f\n\t" /* quiet NaN */
85	    "nop\n\t"
86	    "or	    %%g0,5,%0\n\t" /* signalling NaN */
87	    "2:\n\t"
88	    : "=r" (ret), "=m" (fint), "=r" (tmp), "+f" (f)
89	    :
90	    : "cc");
91
92	return (ret);
93}
94
95extern __GNU_INLINE enum fp_class_type
96fp_class(double d)
97{
98	enum fp_class_type ret;
99	uint64_t dint;		/* Scratch for d-as-long */
100	uint64_t tmp;
101
102	__asm__ __volatile__(
103	    "fabsd  %3,%3\n\t"
104	    "std    %3,%1\n\t"
105	    "ldx    %1,%0\n\t"
106	    "orcc   %%g0,%0,%%g0\n\t"
107	    "be,pn  %%xcc,2f\n\t"
108	    "nop\n\t"
109	    "sethi  %%hi(0x7ff00000),%2\n\t"
110	    "sllx   %2,32,%2\n\t"
111	    "andcc  %0,%2,%%g0\n\t"
112	    "bne,pt %%xcc,1f\n\t"
113	    "nop\n\t"
114	    "or	    %%g0,1,%0\n\t"
115	    "ba	    2f\n\t"
116	    "nop\n\t"
117	    "1:\n\t"
118	    "subcc  %0,%2,%%g0\n\t"
119	    "bge,pn %%xcc,1f\n\t"
120	    "nop\n\t"
121	    "or	    %%g0,2,%0\n\t"
122	    "ba	    2f\n\t"
123	    "nop\n\t"
124	    "1:\n\t"
125	    "andncc %0,%2,%0\n\t"
126	    "bne,pn %%xcc,1f\n\t"
127	    "nop\n\t"
128	    "or	    %%g0,3,%0\n\t"
129	    "ba	    2f\n\t"
130	    "nop\n\t"
131	    "1:\n\t"
132	    "sethi  %%hi(0x00080000),%2\n\t"
133	    "sllx   %2,32,%2\n\t"
134	    "andcc  %0,%2,%%g0\n\t"
135	    "or	    %%g0,4,%0\n\t"
136	    "bne,pt %%xcc,2f\n\t"
137	    "nop\n\t"
138	    "or	    %%g0,5,%0\n\t"
139	    "2:\n\t"
140	    : "=r" (ret), "=m" (dint), "=r" (tmp), "+e" (d)
141	    :
142	    : "cc");
143
144	return (ret);
145}
146
147extern __GNU_INLINE float
148__inline_sqrtf(float f)
149{
150	float ret;
151
152	__asm__ __volatile__("fsqrts %1,%0\n\t" : "=f" (ret) : "f" (f));
153	return (ret);
154}
155
156extern __GNU_INLINE double
157__inline_sqrt(double d)
158{
159	double ret;
160
161	__asm__ __volatile__("fsqrtd %1,%0\n\t" : "=f" (ret) : "f" (d));
162	return (ret);
163}
164
165extern __GNU_INLINE int
166__swapEX(int i)
167{
168	int ret;
169	uint32_t fsr;
170	uint64_t tmp1, tmp2;
171
172	__asm__ __volatile__(
173	    "and  %4,0x1f,%2\n\t"
174	    "sll  %2,5,%2\n\t"	/* shift input to aexc bit location */
175	    ".volatile\n\t"
176	    "st   %%fsr,%1\n\t"
177	    "ld	  %1,%0\n\t"	/* %0 = fsr */
178	    "andn %0,0x3e0,%3\n\t"
179	    "or   %2,%3,%2\n\t"	/* %2 = new fsr */
180	    "st	  %2,%1\n\t"
181	    "ld	  %1,%%fsr\n\t"
182	    "srl  %0,5,%0\n\t"
183	    "and  %0,0x1f,%0\n\t"
184	    ".nonvolatile\n\t"
185	    : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2)
186	    : "r" (i)
187	    : "cc");
188
189	return (ret);
190}
191
192/*
193 * On the SPARC, __swapRP is a no-op; always return 0 for backward
194 * compatibility
195 */
196/* ARGSUSED */
197extern __GNU_INLINE enum fp_precision_type
198__swapRP(enum fp_precision_type i)
199{
200	return (0);
201}
202
203extern __GNU_INLINE enum fp_direction_type
204__swapRD(enum fp_direction_type d)
205{
206	enum fp_direction_type ret;
207	uint32_t fsr;
208	uint64_t tmp1, tmp2, tmp3;
209
210	__asm__ __volatile__(
211	    "and   %5,0x3,%0\n\t"
212	    "sll   %0,30,%2\n\t"	/* shift input to RD bit location */
213	    ".volatile\n\t"
214	    "st    %%fsr,%1\n\t"
215	    "ld	   %1,%0\n\t"		/* %0 = fsr */
216	    /* mask of rounding direction bits */
217	    "sethi %%hi(0xc0000000),%4\n\t"
218	    "andn  %0,%4,%3\n\t"
219	    "or    %2,%3,%2\n\t"	/* %2 = new fsr */
220	    "st	   %2,%1\n\t"
221	    "ld	   %1,%%fsr\n\t"
222	    "srl   %0,30,%0\n\t"
223	    "and   %0,0x3,%0\n\t"
224	    ".nonvolatile\n\t"
225	    : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)
226	    : "r" (d)
227	    : "cc");
228
229	return (ret);
230}
231
232extern __GNU_INLINE int
233__swapTE(int i)
234{
235	int ret;
236	uint32_t fsr;
237	uint64_t tmp1, tmp2, tmp3;
238
239	__asm__ __volatile__(
240	    "and   %5,0x1f,%0\n\t"
241	    "sll   %0,23,%2\n\t"	/* shift input to TEM bit location */
242	    ".volatile\n\t"
243	    "st    %%fsr,%1\n\t"
244	    "ld	   %1,%0\n\t"		/* %0 = fsr */
245	    /* mask of TEM (Trap Enable Mode bits) */
246	    "sethi %%hi(0x0f800000),%4\n\t"
247	    "andn  %0,%4,%3\n\t"
248	    "or    %2,%3,%2\n\t"	/* %2 = new fsr */
249	    "st	   %2,%1\n\t"
250	    "ld	   %1,%%fsr\n\t"
251	    "srl   %0,23,%0\n\t"
252	    "and   %0,0x1f,%0\n\t"
253	    ".nonvolatile\n\t"
254	    : "=r" (ret), "=m" (fsr), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)
255	    : "r" (i)
256	    : "cc");
257
258	return (ret);
259}
260
261
262extern __GNU_INLINE double
263sqrt(double d)
264{
265	return (__inline_sqrt(d));
266}
267
268extern __GNU_INLINE float
269sqrtf(float f)
270{
271	return (__inline_sqrtf(f));
272}
273
274extern __GNU_INLINE double
275fabs(double d)
276{
277	double ret;
278
279	__asm__ __volatile__("fabsd %1,%0\n\t" : "=e" (ret) : "e" (d));
280	return (ret);
281}
282
283extern __GNU_INLINE float
284fabsf(float f)
285{
286	float ret;
287
288	__asm__ __volatile__("fabss %1,%0\n\t" : "=f" (ret) : "f" (f));
289	return (ret);
290}
291
292#ifdef __cplusplus
293}
294#endif
295
296#endif  /* __GNUC__ */
297
298#endif /* _LIBM_INLINES_H */
299