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