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 locallibm.il.  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 __GNU_INLINE float
  49 __inline_sqrtf(float a)
  50 {
  51         float ret;
  52 
  53         __asm__ __volatile__("sqrtss %1, %0\n\t" : "=x" (ret) : "x" (a));
  54         return (ret);
  55 }
  56 
  57 extern __GNU_INLINE double
  58 __inline_sqrt(double a)
  59 {
  60         double ret;
  61 
  62         __asm__ __volatile__("sqrtsd %1, %0\n\t" : "=x" (ret) : "x" (a));
  63         return (ret);
  64 }
  65 
  66 extern __GNU_INLINE double
  67 __ieee754_sqrt(double a)
  68 {
  69         return (__inline_sqrt(a));
  70 }
  71 
  72 /*
  73  * 00 - 24 bits
  74  * 01 - reserved
  75  * 10 - 53 bits
  76  * 11 - 64 bits
  77  */
  78 extern __GNU_INLINE int
  79 __swapRP(int i)
  80 {
  81         int ret;
  82         uint16_t cw;
  83 
  84         __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
  85 
  86         ret = (cw >> 8) & 0x3;
  87         cw = (cw & 0xfcff) | ((i & 0x3) << 8);
  88 
  89         __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
  90 
  91         return (ret);
  92 }
  93 
  94 /*
  95  * 00 - Round to nearest, with even preferred
  96  * 01 - Round down
  97  * 10 - Round up
  98  * 11 - Chop
  99  */
 100 extern __GNU_INLINE enum fp_direction_type
 101 __swap87RD(enum fp_direction_type i)
 102 {
 103         int ret;
 104         uint16_t cw;
 105 
 106         __asm__ __volatile__("fstcw %0\n\t" : "=m" (cw));
 107 
 108         ret = (cw >> 10) & 0x3;
 109         cw = (cw & 0xf3ff) | ((i & 0x3) << 10);
 110 
 111         __asm__ __volatile__("fldcw %0\n\t" : : "m" (cw));
 112 
 113         return (ret);
 114 }
 115 
 116 extern __GNU_INLINE int
 117 abs(int i)
 118 {
 119         int ret;
 120         __asm__ __volatile__(
 121             "movl    %1, %0\n\t"
 122             "negl    %1\n\t"
 123             "cmovnsl %1, %0\n\t"
 124             : "=r" (ret), "+r" (i)
 125             :
 126             : "cc");
 127         return (ret);
 128 }
 129 
 130 extern __GNU_INLINE double
 131 copysign(double d1, double d2)
 132 {
 133         double tmpd;
 134 
 135         __asm__ __volatile__(
 136             "movd %3, %1\n\t"
 137             "andpd %1, %0\n\t"
 138             "andnpd %2, %1\n\t"
 139             "orpd %1, %0\n\t"
 140             : "+&x" (d1), "=&x" (tmpd)
 141             : "x" (d2), "r" (0x7fffffffffffffff));
 142 
 143         return (d1);
 144 }
 145 
 146 extern __GNU_INLINE double
 147 fabs(double d)
 148 {
 149         double tmp;
 150 
 151         __asm__ __volatile__(
 152             "movd  %2, %1\n\t"
 153             "andpd %1, %0"
 154             : "+x" (d), "=&x" (tmp)
 155             : "r" (0x7fffffffffffffff));
 156 
 157         return (d);
 158 }
 159 
 160 extern __GNU_INLINE float
 161 fabsf(float d)
 162 {
 163         __asm__ __volatile__(
 164             "andpd %1, %0"
 165             : "+x" (d)
 166             : "x" (0x7fffffff));
 167 
 168         return (d);
 169 }
 170 
 171 extern __GNU_INLINE int
 172 finite(double d)
 173 {
 174         long ret = 0x7fffffffffffffff;
 175         uint64_t tmp;
 176 
 177         __asm__ __volatile__(
 178             "movq %2, %1\n\t"
 179             "andq %1, %0\n\t"
 180             "movq $0x7ff0000000000000, %1\n\t"
 181             "subq %1, %0\n\t"
 182             "shrq $63, %0\n\t"
 183             : "+r" (ret), "=r" (tmp)
 184             : "x" (d)
 185             : "cc");
 186 
 187         return (ret);
 188 }
 189 
 190 extern __GNU_INLINE int
 191 signbit(double d)
 192 {
 193         long ret;
 194         __asm__ __volatile__(
 195             "movmskpd %1, %0\n\t"
 196             "andq     $1, %0\n\t"
 197             : "=r" (ret)
 198             : "x" (d)
 199             : "cc");
 200         return (ret);
 201 }
 202 
 203 extern __GNU_INLINE double
 204 sqrt(double d)
 205 {
 206         return (__inline_sqrt(d));
 207 }
 208 
 209 extern __GNU_INLINE float
 210 sqrtf(float f)
 211 {
 212         return (__inline_sqrtf(f));
 213 }
 214 
 215 #ifdef __cplusplus
 216 }
 217 #endif
 218 
 219 #endif  /* __GNUC__ */
 220 
 221 #endif /* _LIBM_INLINES_H */