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 #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 __inline_sqrt(double a) 51 { 52 double ret; 53 54 __asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a) : "cc"); 55 return (ret); 56 } 57 58 extern __inline__ double 59 __ieee754_sqrt(double a) 60 { 61 return (__inline_sqrt(a)); 62 } 63 64 extern __inline__ float 65 __inline_sqrtf(float a) 66 { 67 float ret; 68 69 __asm__ __volatile__("fsqrt\n\t" : "=t" (ret) : "0" (a) : "cc"); 70 return (ret); 71 } 72 73 extern __inline__ double 74 __inline_rint(double a) 75 { 76 __asm__ __volatile__( 77 "andl $0x7fffffff,%1\n\t" 78 "cmpl $0x43300000,%1\n\t" 79 "jae 1f\n\t" 80 "frndint\n\t" 81 "1: fwait\n\t" 82 : "+t" (a), "+&r" (_HI_WORD(a)) 83 : 84 : "cc"); 85 86 return (a); 87 } 88 89 /* 90 * 00 - 24 bits 91 * 01 - reserved 92 * 10 - 53 bits 93 * 11 - 64 bits 94 */ 95 extern __inline__ int 96 __swapRP(int i) 97 { 98 int ret; 99 uint16_t cw; 100 101 __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw)); 102 103 ret = (cw >> 8) & 0x3; 104 cw = (cw & 0xfcff) | ((i & 0x3) << 8); 105 106 __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw)); 107 108 return (ret); 109 } 110 111 /* 112 * 00 - Round to nearest, with even preferred 113 * 01 - Round down 114 * 10 - Round up 115 * 11 - Chop 116 */ 117 extern __inline__ enum fp_direction_type 118 __swap87RD(enum fp_direction_type i) 119 { 120 int ret; 121 uint16_t cw; 122 123 __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw)); 124 125 ret = (cw >> 10) & 0x3; 126 cw = (cw & 0xf3ff) | ((i & 0x3) << 10); 127 128 __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw)); 129 130 return (ret); 131 } 132 133 extern __inline__ double 134 ceil(double d) 135 { 136 short rd = __swap87RD(fp_positive); 137 138 __asm__ __volatile__("frndint" : "+t" (d), "+r" (rd) : : "cc"); 139 __swap87RD(rd); 140 141 return (d); 142 } 143 144 extern __inline__ double 145 copysign(double d1, double d2) 146 { 147 __asm__ __volatile__( 148 "andl $0x7fffffff,%0\n\t" /* %0 <-- hi_32(abs(d)) */ 149 "andl $0x80000000,%1\n\t" /* %1[31] <-- sign_bit(d2) */ 150 "orl %1,%0\n\t" /* %0 <-- hi_32(copysign(x,y)) */ 151 : "+&r" (_HI_WORD(d1)), "+r" (_HI_WORD(d2)) 152 : 153 : "cc"); 154 155 return (d1); 156 } 157 158 extern __inline__ double 159 fabs(double d) 160 { 161 __asm__ __volatile__("fabs\n\t" : "+t" (d) : : "cc"); 162 return (d); 163 } 164 165 extern __inline__ float 166 fabsf(float d) 167 { 168 __asm__ __volatile__("fabs\n\t" : "+t" (d) : : "cc"); 169 return (d); 170 } 171 172 extern __inline__ long double 173 fabsl(long double d) 174 { 175 __asm__ __volatile__("fabs\n\t" : "+t" (d) : : "cc"); 176 return (d); 177 } 178 179 extern __inline__ int 180 finite(double d) 181 { 182 int ret = _HI_WORD(d); 183 184 __asm__ __volatile__( 185 "notl %0\n\t" 186 "andl $0x7ff00000,%0\n\t" 187 "negl %0\n\t" 188 "shrl $31,%0\n\t" 189 : "+r" (ret) 190 : 191 : "cc"); 192 return (ret); 193 } 194 195 extern __inline__ double 196 floor(double d) 197 { 198 short rd = __swap87RD(fp_negative); 199 200 __asm__ __volatile__("frndint" : "+t" (d), "+r" (rd) : : "cc"); 201 __swap87RD(rd); 202 203 return (d); 204 } 205 206 extern __inline__ int 207 isnanf(float f) 208 { 209 __asm__ __volatile__( 210 "andl $0x7fffffff,%0\n\t" 211 "negl %0\n\t" 212 "addl $0x7f800000,%0\n\t" 213 "shrl $31,%0\n\t" 214 : "+r" (f) 215 : 216 : "cc"); 217 218 return (f); 219 } 220 221 extern __inline__ double 222 rint(double a) { 223 return (__inline_rint(a)); 224 } 225 226 extern __inline__ double 227 scalbn(double d, int n) 228 { 229 double dummy; 230 231 __asm__ __volatile__( 232 "fildl %2\n\t" /* Convert N to extended */ 233 "fxch\n\t" 234 "fscale\n\t" 235 : "+t" (d), "=u" (dummy) 236 : "m" (n) 237 : "cc"); 238 239 return (d); 240 } 241 242 extern __inline__ int 243 signbit(double d) 244 { 245 return (_HI_WORD(d) >> 31); 246 } 247 248 extern __inline__ int 249 signbitf(float f) 250 { 251 return ((*(uint32_t *)&f) >> 31); 252 } 253 254 extern __inline__ double 255 sqrt(double d) 256 { 257 return (__inline_sqrt(d)); 258 } 259 260 extern __inline__ float 261 sqrtf(float f) 262 { 263 return (__inline_sqrtf(f)); 264 } 265 266 extern __inline__ long double 267 sqrtl(long double ld) 268 { 269 __asm__ __volatile__("fsqrt" : "+t" (ld) : : "cc"); 270 return (ld); 271 } 272 273 extern __inline__ int 274 isnanl(long double ld) 275 { 276 int ret = _HIER_WORD(ld); 277 278 __asm__ __volatile__( 279 "andl $0x00007fff,%0\n\t" 280 "jz 1f\n\t" /* jump if exp is all 0 */ 281 "xorl $0x00007fff,%0\n\t" 282 "jz 2f\n\t" /* jump if exp is all 1 */ 283 "testl $0x80000000,%1\n\t" 284 "jz 3f\n\t" /* jump if leading bit is 0 */ 285 "movl $0,%0\n\t" 286 "jmp 1f\n\t" 287 "2:\n\t" /* note that %0 = 0 from before */ 288 "cmpl $0x80000000,%1\n\t" /* what is first half of significand? */ 289 "jnz 3f\n\t" /* jump if not equal to 0x80000000 */ 290 "testl $0xffffffff,%2\n\t" /* is second half of significand 0? */ 291 "jnz 3f\n\t" /* jump if not equal to 0 */ 292 "jmp 1f\n\t" 293 "3:\n\t" 294 "movl $1,%0\n\t" 295 "1:\n\t" 296 : "+&r" (ret) 297 : "r" (_HI_WORD(ld)), "r" (_LO_WORD(ld)) 298 : "cc"); 299 300 return (ret); 301 } 302 303 #ifdef __cplusplus 304 } 305 #endif 306 307 #endif /* __GNUC__ */ 308 309 #endif /* _LIBM_INLINES_H */