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