xref: /illumos-gate/usr/src/lib/libm/amd64/src/libm_inlines.h (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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
42 extern "C" {
43 #endif
44 
45 #include <sys/types.h>
46 #include <sys/ieeefp.h>
47 
48 extern __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 
57 extern __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 
66 extern __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  */
78 extern __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  */
100 extern __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 
116 extern __GNU_INLINE int
117 abs(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 
130 extern __GNU_INLINE double
131 copysign(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 
146 extern __GNU_INLINE double
147 fabs(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 
160 extern __GNU_INLINE float
161 fabsf(float d)
162 {
163 	__asm__ __volatile__(
164 	    "andpd %1, %0"
165 	    : "+x" (d)
166 	    : "x" (0x7fffffff));
167 
168 	return (d);
169 }
170 
171 extern __GNU_INLINE int
172 finite(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 
190 extern __GNU_INLINE int
191 signbit(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 
203 extern __GNU_INLINE double
204 sqrt(double d)
205 {
206 	return (__inline_sqrt(d));
207 }
208 
209 extern __GNU_INLINE float
210 sqrtf(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