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