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 2011 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 /*
  26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 /*
  31  * Copyright 2011, Richard Lowe.
  32  */
  33 
  34 /* Functions in this file are duplicated in libm.m4.  Keep them in sync */
  35 
  36 #ifndef _LIBM_INLINES_H
  37 #define _LIBM_INLINES_H
  38 
  39 #ifdef __GNUC__
  40 
  41 #ifdef __cplusplus
  42 extern "C" {
  43 #endif
  44 
  45 #include <sys/types.h>
  46 #include <sys/ieeefp.h>
  47 
  48 extern __inline__ double
  49 __ieee754_sqrt(double a)
  50 {
  51         double ret;
  52 
  53         __asm__ __volatile__("sqrtsd %1, %0\n\t" : "=x" (ret) : "x" (a));
  54         return (ret);
  55 }
  56 
  57 extern __inline__ float
  58 __inline_sqrtf(float a)
  59 {
  60         float ret;
  61 
  62         __asm__ __volatile__("sqrtss %1, %0\n\t" : "=x" (ret) : "x" (a));
  63         return (ret);
  64 }
  65 
  66 extern __inline__ double
  67 __inline_sqrt(double a)
  68 {
  69         double ret;
  70 
  71         __asm__ __volatile__("sqrtsd %1, %0\n\t" : "=x" (ret) : "x" (a));
  72         return (ret);
  73 }
  74 
  75 /* XXX: Not actually called */
  76 extern __inline__ short
  77 __inline_fstsw(void)
  78 {
  79         short ret;
  80 
  81         __asm__ __volatile__("fstsw %0\n\t" : "=r" (ret));
  82         return (ret);
  83 }
  84 
  85 /*
  86  * 00 - 24 bits
  87  * 01 - reserved
  88  * 10 - 53 bits
  89  * 11 - 64 bits
  90  */
  91 extern __inline__ int
  92 __swapRP(int i)
  93 {
  94         int ret;
  95         uint16_t cw;
  96 
  97         __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
  98 
  99         ret = (cw >> 8) & 0x3;
 100         cw = (cw & 0xfcff) | ((i & 0x3) << 8);
 101 
 102         __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
 103 
 104         return (ret);
 105 }
 106 
 107 /*
 108  * 00 - Round to nearest, with even preferred
 109  * 01 - Round down
 110  * 10 - Round up
 111  * 11 - Chop
 112  */
 113 extern __inline__ enum fp_direction_type
 114 __swap87RD(enum fp_direction_type i)
 115 {
 116         int ret;
 117         uint16_t cw;
 118 
 119         __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
 120 
 121         ret = (cw >> 10) & 0x3;
 122         cw = (cw & 0xf3ff) | ((i & 0x3) << 10);
 123 
 124         __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
 125 
 126         return (ret);
 127 }
 128 
 129 extern __inline__ int
 130 abs(int i)
 131 {
 132         int ret;
 133         __asm__ __volatile__(
 134             "movl    %1,%0\n\t"
 135             "negl    %1\n\t"
 136             "cmovnsl %1,%0\n\t"
 137             : "=r" (ret), "+r" (i));
 138         return (ret);
 139 }
 140 
 141 extern __inline__ double
 142 copysign(double d1, double d2)
 143 {
 144         double ret;
 145 
 146         __asm__ __volatile__(
 147             "movq   $0x7fffffffffffffff,%%rax\n\t"
 148             "movd   %%rax,%%xmm2\n\t"
 149             "andpd  %%xmm2,%0\n\t"
 150             "andnpd %1,%%xmm2\n\t"
 151             "orpd   %%xmm2,%0\n\t"
 152             : "=x" (ret)
 153             : "x" (d2), "0" (d1)
 154             : "xmm2", "rax");
 155 
 156         return (ret);
 157 }
 158 
 159 extern __inline__ double
 160 d_sqrt_(double *d)
 161 {
 162         double ret;
 163         __asm__ __volatile__(
 164             "movlpd %1,%0\n\t"
 165             "sqrtsd %0,%0"
 166             : "=x" (ret)
 167             : "m" (*d));
 168         return (ret);
 169 }
 170 
 171 extern __inline__ double
 172 fabs(double d)
 173 {
 174         double ret;
 175 
 176         __asm__ __volatile__(
 177             "movq  $0x7fffffffffffffff,%%rax\n\t"
 178             "movd  %%rax,%%xmm1\n\t"
 179             "andpd %%xmm1,%0"
 180             : "=x" (ret)
 181             : "0" (d)
 182             : "rax", "xmm1");
 183 
 184         return (ret);
 185 }
 186 
 187 extern __inline__ float
 188 fabsf(float d)
 189 {
 190         float ret;
 191 
 192         __asm__ __volatile__(
 193             "andpd %2,%0"
 194             : "=x" (ret)
 195             : "0" (d), "x" (0x7fffffff));
 196 
 197         return (ret);
 198 }
 199 
 200 extern __inline__ int
 201 finite(double d)
 202 {
 203         long ret;                   /* A long, so gcc chooses an %r* for %0 */
 204 
 205         __asm__ __volatile__(
 206             "movq %1,%%rcx\n\t"
 207             "movq $0x7fffffffffffffff,%0\n\t"
 208             "andq %%rcx,%0\n\t"
 209             "movq $0x7ff0000000000000,%%rcx\n\t"
 210             "subq %%rcx,%0\n\t"
 211             "shrq $63,%0\n\t"
 212             : "=r" (ret)
 213             : "x" (d)
 214             : "rcx");
 215 
 216         return (ret);
 217 }
 218 
 219 extern __inline__ float
 220 r_sqrt_(float *f)
 221 {
 222         float ret;
 223 
 224         __asm__ __volatile__(
 225             "movss  %1,%0\n\t"
 226             "sqrtss %0,%0\n\t"
 227             : "+x" (ret)
 228             : "m" (*f));
 229         return (ret);
 230 }
 231 
 232 extern __inline__ int
 233 signbit(double d)
 234 {
 235         long ret;
 236         __asm__ __volatile__(
 237             "movmskpd %1,%0\n\t"
 238             "andq     $1, %0\n\t"
 239             : "=r" (ret)
 240             : "x" (d));
 241         return (ret);
 242 }
 243 
 244 extern __inline__ int
 245 signbitf(float f)
 246 {
 247         int ret;
 248         __asm__ __volatile__(
 249             "movskps %1,%0\n\t"
 250             "andq    $1, %0\n\t"
 251             : "=r" (ret)
 252             : "x" (f));
 253         return (ret);
 254 }
 255 
 256 extern __inline__ double
 257 sqrt(double d)
 258 {
 259         double ret;
 260 
 261         __asm__ __volatile__(
 262             "sqrtsd %0, %0"
 263             : "=x" (ret)
 264             : "0" (d));
 265         return (ret);
 266 }
 267 
 268 extern __inline__ float
 269 sqrtf(float f)
 270 {
 271         float ret;
 272 
 273         __asm__ __volatile__(
 274             "sqrtss %0, %0"
 275             : "=x" (ret)
 276             : "0" (f));
 277         return (ret);
 278 }
 279 
 280 #ifdef __cplusplus
 281 }
 282 #endif
 283 
 284 #endif  /* __GNUC__ */
 285 
 286 #endif /* _LIBM_INLINES_H */