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 2011 Nexenta Systems, Inc.  All rights reserved.
24 */
25/*
26 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27 * Use is subject to license terms.
28 */
29
30/*
31 * Copyright 2011, Richard Lowe.
32 */
33
34/* Functions in this file are duplicated in locallibm.il.  Keep them in sync */
35
36#ifndef _LIBM_INLINES_H
37#define	_LIBM_INLINES_H
38
39#ifdef __GNUC__
40
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45#include <sys/types.h>
46#include <sys/ieeefp.h>
47
48extern __GNU_INLINE float
49__inline_sqrtf(float a)
50{
51	float ret;
52
53	__asm__ __volatile__("sqrtss %1, %0\n\t" : "=x" (ret) : "x" (a));
54	return (ret);
55}
56
57extern __GNU_INLINE double
58__inline_sqrt(double a)
59{
60	double ret;
61
62	__asm__ __volatile__("sqrtsd %1, %0\n\t" : "=x" (ret) : "x" (a));
63	return (ret);
64}
65
66extern __GNU_INLINE double
67__ieee754_sqrt(double a)
68{
69	return (__inline_sqrt(a));
70}
71
72/*
73 * 00 - 24 bits
74 * 01 - reserved
75 * 10 - 53 bits
76 * 11 - 64 bits
77 */
78extern __GNU_INLINE int
79__swapRP(int i)
80{
81	int ret;
82	uint16_t cw;
83
84	__asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
85
86	ret = (cw >> 8) & 0x3;
87	cw = (cw & 0xfcff) | ((i & 0x3) << 8);
88
89	__asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
90
91	return (ret);
92}
93
94/*
95 * 00 - Round to nearest, with even preferred
96 * 01 - Round down
97 * 10 - Round up
98 * 11 - Chop
99 */
100extern __GNU_INLINE enum fp_direction_type
101__swap87RD(enum fp_direction_type i)
102{
103	int ret;
104	uint16_t cw;
105
106	__asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
107
108	ret = (cw >> 10) & 0x3;
109	cw = (cw & 0xf3ff) | ((i & 0x3) << 10);
110
111	__asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
112
113	return (ret);
114}
115
116extern __GNU_INLINE int
117abs(int i)
118{
119	int ret;
120	__asm__ __volatile__(
121	    "movl    %1, %0\n\t"
122	    "negl    %1\n\t"
123	    "cmovnsl %1, %0\n\t"
124	    : "=r" (ret), "+r" (i)
125	    :
126	    : "cc");
127	return (ret);
128}
129
130extern __GNU_INLINE double
131copysign(double d1, double d2)
132{
133	double tmpd;
134
135	__asm__ __volatile__(
136	    "movd %3, %1\n\t"
137	    "andpd %1, %0\n\t"
138	    "andnpd %2, %1\n\t"
139	    "orpd %1, %0\n\t"
140	    : "+&x" (d1), "=&x" (tmpd)
141	    : "x" (d2), "r" (0x7fffffffffffffff));
142
143	return (d1);
144}
145
146extern __GNU_INLINE double
147fabs(double d)
148{
149	double tmp;
150
151	__asm__ __volatile__(
152	    "movd  %2, %1\n\t"
153	    "andpd %1, %0"
154	    : "+x" (d), "=&x" (tmp)
155	    : "r" (0x7fffffffffffffff));
156
157	return (d);
158}
159
160extern __GNU_INLINE float
161fabsf(float d)
162{
163	__asm__ __volatile__(
164	    "andpd %1, %0"
165	    : "+x" (d)
166	    : "x" (0x7fffffff));
167
168	return (d);
169}
170
171extern __GNU_INLINE int
172finite(double d)
173{
174	long ret = 0x7fffffffffffffff;
175	uint64_t tmp;
176
177	__asm__ __volatile__(
178	    "movq %2, %1\n\t"
179	    "andq %1, %0\n\t"
180	    "movq $0x7ff0000000000000, %1\n\t"
181	    "subq %1, %0\n\t"
182	    "shrq $63, %0\n\t"
183	    : "+r" (ret), "=r" (tmp)
184	    : "x" (d)
185	    : "cc");
186
187	return (ret);
188}
189
190extern __GNU_INLINE int
191signbit(double d)
192{
193	long ret;
194	__asm__ __volatile__(
195	    "movmskpd %1, %0\n\t"
196	    "andq     $1, %0\n\t"
197	    : "=r" (ret)
198	    : "x" (d)
199	    : "cc");
200	return (ret);
201}
202
203extern __GNU_INLINE double
204sqrt(double d)
205{
206	return (__inline_sqrt(d));
207}
208
209extern __GNU_INLINE float
210sqrtf(float f)
211{
212	return (__inline_sqrtf(f));
213}
214
215#ifdef __cplusplus
216}
217#endif
218
219#endif  /* __GNUC__ */
220
221#endif /* _LIBM_INLINES_H */
222