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 #include <sys/types.h>
  39 #include <sys/ieeefp.h>
  40 
  41 #ifdef __cplusplus
  42 extern "C" {
  43 #endif
  44 
  45 extern __inline__ double
  46 __inline_sqrt(double d)
  47 {
  48         double ret;
  49 
  50         __asm__ __volatile__("fsqrtd %0,%0\n\t" : "=e" (ret) : "0" (d));
  51         return (ret);
  52 }
  53 
  54 extern __inline__ float
  55 __inline_sqrtf(float f)
  56 {
  57         float ret;
  58 
  59         __asm__ __volatile__("fsqrts %0,%0\n\t" : "=f" (ret) : "0" (f));
  60         return (ret);
  61 }
  62 
  63 extern __inline__ enum fp_class_type
  64 fp_classf(float f)
  65 {
  66         enum fp_class_type ret;
  67 
  68         __asm__ __volatile__(
  69             "sethi  %%hi(0x80000000),%%o2\n\t"
  70             "andncc %0,%%o2,%0\n\t"
  71             "bne    1f\n\t"
  72             "nop\n\t"
  73             "mov    0,%0\n\t"
  74             "ba 2f\n\t"             /* x is 0 */
  75             "nop\n\t"
  76             "1:\n\t"
  77             "sethi  %%hi(0x7f800000),%%o2\n\t"
  78             "andcc  %0,%%o2,%%g0\n\t"
  79             "bne    1f\n\t"
  80             "nop\n\t"
  81             "mov    1,%0\n\t"
  82             "ba     2f\n\t"         /* x is subnormal */
  83             "nop\n\t"
  84             "1:\n\t"
  85             "cmp    %0,%%o2\n\t"
  86             "bge    1f\n\t"
  87             "nop\n\t"
  88             "mov    2,%0\n\t"
  89             "ba     2f\n\t"         /* x is normal */
  90             "nop\n\t"
  91             "1:\n\t"
  92             "bg     1f\n\t"
  93             "nop\n\t"
  94             "mov    3,%0\n\t"
  95             "ba     2f\n\t"         /* x is __infinity */
  96             "nop\n\t"
  97             "1:\n\t"
  98             "sethi  %%hi(0x00400000),%%o2\n\t"
  99             "andcc  %0,%%o2,%%g0\n\t"
 100             "mov    4,%0\n\t"       /* x is quiet NaN */
 101             "bne    2f\n\t"
 102             "nop\n\t"
 103             "mov    5,%0\n\t"       /* x is signaling NaN */
 104             "2:\n\t"
 105             : "=r" (ret)
 106             : "0" (f)
 107             : "o2");
 108         return (ret);
 109 }
 110 
 111 #define _HI_WORD(x)     ((uint32_t *)&x)[0]
 112 #define _LO_WORD(x)     ((uint32_t *)&x)[1]
 113 
 114 extern __inline__ enum fp_class_type
 115 fp_class(double d)
 116 {
 117         enum fp_class_type ret;
 118 
 119         __asm__ __volatile__(
 120             "sethi %%hi(0x80000000),%%o2\n\t" /* o2 gets 80000000 */
 121             "andn  %0,%%o2,%0\n\t"            /* o0-o1 gets abs(x) */
 122             "orcc  %0,%2,%%g0\n\t"            /* set cc as x is zero/nonzero */
 123             "bne   1f\n\t"                    /* branch if x is nonzero */
 124             "nop\n\t"
 125             "mov   0,%0\n\t"
 126             "ba    2f\n\t"                    /* x is 0 */
 127             "nop\n\t"
 128             "1:\n\t"
 129             "sethi %%hi(0x7ff00000),%%o2\n\t" /* o2 gets 7ff00000 */
 130             "andcc %0,%%o2,%%g0\n\t"          /* cc set by __exp field of x */
 131             "bne   1f\n\t"                    /* branch if normal or max __exp */
 132             "nop\n\t"
 133             "mov   1,%0\n\t"
 134             "ba    2f\n\t"                    /* x is subnormal */
 135             "nop\n\t"
 136             "1:\n\t"
 137             "cmp   %0,%%o2\n\t"
 138             "bge   1f\n\t"                    /* branch if x is max __exp */
 139             "nop\n\t"
 140             "mov   2,%0\n\t"
 141             "ba    2f\n\t"                    /* x is normal */
 142             "nop\n\t"
 143             "1:\n\t"
 144             "andn  %0,%%o2,%0\n\t"            /* o0 gets msw __significand field */
 145             "orcc  %0,%2,%%g0\n\t"            /* set cc by OR __significand */
 146             "bne   1f\n\t"                    /* Branch if __nan */
 147             "nop\n\t"
 148             "mov   3,%0\n\t"
 149             "ba    2f\n\t"                    /* x is __infinity */
 150             "nop\n\t"
 151             "1:\n\t"
 152             "sethi %%hi(0x00080000),%%o2\n\t"
 153             "andcc %0,%%o2,%%g0\n\t"          /* set cc by quiet/sig bit */
 154             "be    1f\n\t"                    /* Branch if signaling */
 155             "nop\n\t"
 156             "mov   4,%0\n\t"                  /* x is quiet NaN */
 157             "ba    2f\n\t"
 158             "nop\n\t"
 159             "1:\n\t"
 160             "mov   5,%0\n\t"                  /* x is signaling NaN */
 161             "2:\n\t"
 162             : "=r" (ret)
 163             : "0" (_HI_WORD(d)), "r" (_LO_WORD(d))
 164             : "o2");
 165 
 166         return (ret);
 167 }
 168 
 169 extern __inline__ int
 170 __swapEX(int i)
 171 {
 172         int ret;
 173         uint32_t fsr;
 174 
 175         __asm__ __volatile__(
 176             "and  %0,0x1f,%%o1\n\t"
 177             "sll  %%o1,5,%%o1\n\t"    /*  input to aexc bit location */
 178             ".volatile\n\t"
 179             "st   %%fsr,%2\n\t"
 180             "ld   %2,%0\n\t"          /* = fsr */
 181             "andn %0,0x3e0,%%o2\n\t"
 182             "or   %%o1,%%o2,%%o1\n\t" /* o1 = new fsr */
 183             "st   %%o1,%2\n\t"
 184             "ld   %2,%%fsr\n\t"
 185             "srl  %0,5,%0\n\t"
 186             "and  %0,0x1f,%0\n\t"
 187             ".nonvolatile\n\t"
 188             : "=r" (ret)
 189             : "0" (i), "m" (fsr)
 190             : "o1", "o2");
 191 
 192         return (ret);
 193 }
 194 
 195 /*
 196  * On the SPARC, __swapRP is a no-op; always return 0 for backward
 197  * compatibility
 198  */
 199 /* ARGSUSED */
 200 extern __inline__ enum fp_precision_type
 201 __swapRP(enum fp_precision_type i)
 202 {
 203         return (0);
 204 }
 205 
 206 extern __inline__ enum fp_direction_type
 207 __swapRD(enum fp_direction_type d)
 208 {
 209         enum fp_direction_type ret;
 210         uint32_t fsr;
 211 
 212         __asm__ __volatile__(
 213             "and  %0,0x3,%0\n\t"
 214             "sll  %0,30,%%o1\n\t"      /* input to RD bit location */
 215             ".volatile\n\t"
 216             "st   %%fsr,%2\n\t"
 217             "ld   %2,%0\n\t"           /* o0 = fsr */
 218             "set  0xc0000000,%%o4\n\t" /* mask of rounding direction bits */
 219             "andn %0,%%o4,%%o2\n\t"
 220             "or   %%o1,%%o2,%%o1\n\t"  /* o1 = new fsr */
 221             "st   %%o1,%2\n\t"
 222             "ld   %2,%%fsr\n\t"
 223             "srl  %0,30,%0\n\t"
 224             "and  %0,0x3,%0\n\t"
 225             ".nonvolatile\n\t"
 226             : "=r" (ret)
 227             : "0" (d), "m" (fsr)
 228             : "o1", "o2", "o4");
 229 
 230         return (ret);
 231 }
 232 
 233 extern __inline__ int
 234 __swapTE(int i)
 235 {
 236         int ret;
 237         uint32_t fsr;
 238         
 239         __asm__ __volatile__(
 240             "and  %0,0x1f,%0\n\t"
 241             "sll  %0,23,%%o1\n\t"      /* input to TEM bit location */
 242             ".volatile\n\t"
 243             "st   %%fsr,%2\n\t"
 244             "ld   %2,%0\n\t"           /* o0 = fsr */
 245             "set  0x0f800000,%%o4\n\t" /* mask of TEM (Trap Enable Mode bits) */
 246             "andn %0,%%o4,%%o2\n\t"       
 247             "or   %%o1,%%o2,%%o1\n\t"  /* o1 = new fsr */
 248             "st   %%o1,%2\n\t"
 249             "ld   %2,%%fsr\n\t"
 250             "srl  %0,23,%0\n\t"
 251             "and  %0,0x1f,%0\n\t"
 252             ".nonvolatile\n\t"
 253             : "=r" (ret)
 254             : "0" (i), "m" (fsr)
 255             : "o1", "o2", "o4");
 256 
 257         return (ret);
 258 }
 259 
 260 extern __inline__ double
 261 sqrt(double d)
 262 {
 263     double ret;
 264 
 265     __asm__ __volatile__("fsqrtd %0,%0\n\t" : "=f" (ret) : "0" (d));
 266     return (ret);
 267 }
 268 
 269 extern __inline__ float
 270 sqrtf(float f)
 271 {
 272     float ret;
 273 
 274     __asm__ __volatile__("fsqrts %0,%0\n\t" : "=f" (ret) : "0" (f));
 275     return (ret);
 276 }
 277 
 278 extern __inline__ double
 279 fabs(double d)
 280 {
 281     double ret;
 282 
 283     __asm__ __volatile__("fabsd %0,%0\n\t" : "=e" (ret) : "0" (d));
 284     return (ret);
 285 }
 286 
 287 extern __inline__ float
 288 fabsf(float f)
 289 {
 290     float ret;
 291 
 292     __asm__ __volatile__("fabss %0,%0\n\t" : "=f" (ret) : "0" (f));
 293     return (ret);
 294 }
 295 
 296 #ifdef __cplusplus
 297 }
 298 #endif
 299 
 300 #endif  /* __GNUC */
 301 
 302 #endif /* _LIBM_INLINES_H */