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