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 */