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 libm.m4. Keep them in sync */ 32 33 #ifndef _LIBM_INLINES_H 34 #define _LIBM_INLINES_H 35 36 #ifdef __GNUC__ 37 38 #ifdef __cplusplus 39 extern "C" { 40 #endif 41 42 #include <sys/types.h> 43 #include <sys/ieeefp.h> 44 45 #define _LO_WORD(x) ((uint32_t *)&x)[0] 46 #define _HI_WORD(x) ((uint32_t *)&x)[1] 47 #define _HIER_WORD(x) ((uint32_t *)&x)[2] 48 49 extern __inline__ double 50 __ieee754_sqrt(double a) 51 { 52 double ret; 53 54 __asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a)); 55 return (ret); 56 } 57 58 extern __inline__ double 59 __inline_sqrt(double a) 60 { 61 double ret; 62 63 __asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a)); 64 return (ret); 65 } 66 67 extern __inline__ double 68 __d_sqrt_(double *a) 69 { 70 double ret; 71 72 __asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (*a)); 73 return (ret); 74 } 75 76 extern __inline__ float 77 __inline_sqrtf(float a) 78 { 79 float ret; 80 81 __asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a)); 82 return (ret); 83 } 84 85 extern __inline__ double 86 __inline_rint(double a) 87 { 88 double ret; 89 90 __asm__ __volatile__( 91 "andl $0x7fffffff,%2\n\t" 92 "cmpl $0x43300000,%2\n\t" 93 "jae 1f\n\t" 94 "frndint\n\t" 95 "1: fwait\n\t" 96 : "=t" (ret) 97 : "0" (a), "r" (_HI_WORD(a))); 98 99 return (ret); 100 } 101 102 extern __inline__ short 103 __inline_fstsw(void) 104 { 105 short ret; 106 107 __asm__ __volatile__("fstsw %0\n\t" : "=r" (ret)); 108 return (ret); 109 } 110 111 /* 112 * 00 - 24 bits 113 * 01 - reserved 114 * 10 - 53 bits 115 * 11 - 64 bits 116 */ 117 extern __inline__ int 118 __swapRP(int i) 119 { 120 int ret; 121 uint16_t cw; 122 123 __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw)); 124 125 ret = (cw >> 8) & 0x3; 126 cw = (cw & 0xfcff) | ((i & 0x3) << 8); 127 128 __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw)); 129 130 return (ret); 131 } 132 133 /* 134 * 00 - Round to nearest, with even preferred 135 * 01 - Round down 136 * 10 - Round up 137 * 11 - Chop 138 */ 139 extern __inline__ enum fp_direction_type 140 __swap87RD(enum fp_direction_type i) 141 { 142 int ret; 143 uint16_t cw; 144 145 __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw)); 146 147 ret = (cw >> 10) & 0x3; 148 cw = (cw & 0xf3ff) | ((i & 0x3) << 10); 149 150 __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw)); 151 152 return (ret); 153 } 154 155 extern __inline__ double 156 ceil(double d) 157 { 158 double ret; 159 short rd = __swap87RD(fp_positive); 160 161 __asm__ __volatile__("frndint" : "=t" (ret) : "0" (d)); 162 __swap87RD(rd); 163 164 return (ret); 165 } 166 167 extern __inline__ double 168 copysign(double d1, double d2) 169 { 170 __asm__ __volatile__( 171 "andl $0x7fffffff,%0\n\t" /* %0 <-- hi_32(abs(d)) */ 172 "andl $0x80000000,%1\n\t" /* %1[31] <-- sign_bit(d2) */ 173 "orl %1,%0\n\t" /* %0 <-- hi_32(copysign(x,y)) */ 174 : "+r" (_HI_WORD(d1)) 175 : "r" (_HI_WORD(d2))); 176 177 return (d1); 178 } 179 180 extern __inline__ double 181 fabs(double d) 182 { 183 double ret; 184 185 __asm__ __volatile__("fabs\n\t" : "=t" (ret) : "0" (d)); 186 return (ret); 187 } 188 189 extern __inline__ float 190 fabsf(float d) 191 { 192 float ret; 193 194 __asm__ __volatile__("fabs\n\t" : "=t" (ret) : "0" (d)); 195 return (ret); 196 } 197 198 extern __inline__ long double 199 fabsl(long double d) 200 { 201 long double ret; 202 203 __asm__ __volatile__("fabs\n\t" : "=t" (ret) : "0" (d)); 204 return (ret); 205 } 206 207 extern __inline__ int 208 finite(double d) 209 { 210 int ret; 211 212 __asm__ __volatile__( 213 "notl %1\n\t" 214 "andl $0x7ff00000,%1\n\t" 215 "negl %1\n\t" 216 "shrl $31,%1\n\t" 217 : "=r" (ret) 218 : "0" (_HI_WORD(d))); 219 return (ret); 220 } 221 222 extern __inline__ double 223 floor(double d) 224 { 225 double ret; 226 short rd = __swap87RD(fp_negative); 227 228 __asm__ __volatile__("frndint" : "=t" (ret) : "0" (d)); 229 __swap87RD(rd); 230 231 return (ret); 232 } 233 234 /* 235 * branchless __isnan 236 * ((0x7ff00000-[((lx|-lx)>>31)&1]|ahx)>>31)&1 = 1 iff x is NaN 237 */ 238 extern __inline__ int 239 isnan(double d) 240 { 241 int ret; 242 243 __asm__ __volatile__( 244 "movl %1,%%ecx\n\t" 245 "negl %%ecx\n\t" /* ecx <-- -lo_32(x) */ 246 "orl %%ecx,%1\n\t" 247 "shrl $31,%1\n\t" /* 1 iff lx != 0 */ 248 "andl $0x7fffffff,%2\n\t" /* ecx <-- hi_32(abs(x)) */ 249 "orl %2,%1\n\t" 250 "subl $0x7ff00000,%1\n\t" 251 "negl %1\n\t" 252 "shrl $31,%1\n\t" 253 : "=r" (ret) 254 : "0" (_HI_WORD(d)), "r" (_LO_WORD(d)) 255 : "ecx"); 256 257 return (ret); 258 } 259 260 extern __inline__ int 261 isnanf(float f) 262 { 263 int ret; 264 265 __asm__ __volatile__( 266 "andl $0x7fffffff,%0\n\t" 267 "negl %0\n\t" 268 "addl $0x7f800000,%0\n\t" 269 "shrl $31,%0\n\t" 270 : "=r" (ret) 271 : "0" (f)); 272 273 return (ret); 274 } 275 276 extern __inline__ int 277 isinf(double d) 278 { 279 int ret; 280 281 __asm__ __volatile__( 282 "andl $0x7fffffff,%1\n\t" /* set first bit to 0 */ 283 "cmpl $0x7ff00000,%1\n\t" 284 "pushfl\n\t" 285 "popl %0\n\t" 286 "cmpl $0,%2\n\t" /* is lo_32(x) = 0? */ 287 "pushfl\n\t" 288 "popl %2\n\t" /* bit 6 of ecx <-- lo_32(x) == 0 */ 289 "andl %2,%0\n\t" 290 "andl $0x40,%0\n\t" 291 "shrl $6,%0\n\t" 292 : "=r" (ret) 293 : "0" (_HI_WORD(d)), "r" (_LO_WORD(d))); 294 295 return (ret); 296 } 297 298 extern __inline__ double 299 rint(double a) { 300 double ret; 301 302 __asm__ __volatile__( 303 "andl $0x7fffffff,%2\n\t" 304 "cmpl $0x43300000,%2\n\t" 305 "jae 1f\n\t" 306 "frndint\n\t" 307 "1: fwait\n\t" 308 : "=t" (ret) 309 : "0" (a), "r" (_HI_WORD(a))); 310 311 return (ret); 312 } 313 314 extern __inline__ double 315 scalbn(double d, int n) 316 { 317 double ret, dummy; 318 319 __asm__ __volatile__( 320 "fildl %3\n\t" /* Convert N to extended */ 321 "fxch\n\t" 322 "fscale\n\t" 323 : "=t" (ret), "=u" (dummy) 324 : "0" (d), "m" (n)); 325 326 return (ret); 327 } 328 329 extern __inline__ int 330 signbit(double d) 331 { 332 return (_HI_WORD(d) >> 31); 333 } 334 335 extern __inline__ int 336 signbitf(float f) 337 { 338 return ((*(uint32_t *)&f) >> 31); 339 } 340 341 extern __inline__ double 342 sqrt(double d) 343 { 344 double ret; 345 __asm__ __volatile__("fsqrt" : "=t" (ret) : "0" (d)); 346 return (ret); 347 } 348 349 extern __inline__ float 350 sqrtf(float f) 351 { 352 float ret; 353 __asm__ __volatile__("fsqrt" : "=t" (ret) : "0" (f)); 354 return (ret); 355 } 356 357 extern __inline__ long double 358 sqrtl(long double ld) 359 { 360 long double ret; 361 __asm__ __volatile__("fsqrt" : "=t" (ret) : "0" (ld)); 362 return (ret); 363 } 364 365 extern __inline__ int 366 isnanl(long double ld) 367 { 368 int ret; 369 370 __asm__ __volatile__( 371 "andl $0x00007fff,%1\n\t" 372 "jz 1f\n\t" /* jump if __exp is all 0 */ 373 "xorl $0x00007fff,%1\n\t" 374 "jz 2f\n\t" /* jump if __exp is all 1 */ 375 "testl $0x80000000,%2\n\t" 376 "jz 3f\n\t" /* jump if leading bit is 0 */ 377 "movl $0,%1\n\t" 378 "jmp 1f\n\t" 379 "2:\n\t" /* note that %eax = 0 from before */ 380 "cmpl $0x80000000,%2\n\t" /* what is first half of __significand? */ 381 "jnz 3f\n\t" /* jump if not equal to 0x80000000 */ 382 "testl $0xffffffff,%3\n\t" /* is second half of __significand 0? */ 383 "jnz 3f\n\t" /* jump if not equal to 0 */ 384 "jmp 1f\n\t" 385 "3:\n\t" 386 "movl $1,%1\n\t" 387 "1:\n\t" 388 : "=r" (ret) 389 : "0" (_HIER_WORD(ld)), "r" (_HI_WORD(ld)), "r" (_LO_WORD(ld))); 390 391 return (ret); 392 } 393 394 #ifdef __cplusplus 395 } 396 #endif 397 398 #endif /* __GNUC__ */ 399 400 #endif /* _LIBM_INLINES_H */