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