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