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