1 /* 2 ** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com> 3 ** 4 ** This program is free software; you can redistribute it and/or modify 5 ** it under the terms of the GNU Lesser General Public License as published by 6 ** the Free Software Foundation; either version 2.1 of the License, or 7 ** (at your option) any later version. 8 ** 9 ** This program is distributed in the hope that it will be useful, 10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 ** GNU Lesser General Public License for more details. 13 ** 14 ** You should have received a copy of the GNU Lesser General Public License 15 ** along with this program; if not, write to the Free Software 16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19 /* Version 1.5 */ 20 21 #ifndef FLOAT_CAST_HEADER 22 #define FLOAT_CAST_HEADER 23 24 /*============================================================================ 25 ** On Intel Pentium processors (especially PIII and probably P4), converting 26 ** from float to int is very slow. To meet the C specs, the code produced by 27 ** most C compilers targeting Pentium needs to change the FPU rounding mode 28 ** before the float to int conversion is performed. 29 ** 30 ** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It 31 ** is this flushing of the pipeline which is so slow. 32 ** 33 ** Fortunately the ISO C99 specifications define the functions lrint, lrintf, 34 ** llrint and llrintf which fix this problem as a side effect. 35 ** 36 ** On Unix-like systems, the configure process should have detected the 37 ** presence of these functions. If they weren't found we have to replace them 38 ** here with a standard C cast. 39 */ 40 41 /* 42 ** The C99 prototypes for lrint and lrintf are as follows: 43 ** 44 ** long int lrintf (float x) ; 45 ** long int lrint (double x) ; 46 */ 47 48 // MEANX #include "xonfig.h" 49 50 /* 51 ** The presence of the required functions are detected during the configure 52 ** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in 53 ** the xonfig.h file. 54 */ 55 56 #define HAVE_LRINT_REPLACEMENT 0 57 58 #if (HAVE_LRINT && HAVE_LRINTF) 59 60 /* 61 ** These defines enable functionality introduced with the 1999 ISO C 62 ** standard. They must be defined before the inclusion of math.h to 63 ** engage them. If optimisation is enabled, these functions will be 64 ** inlined. With optimisation switched off, you have to link in the 65 ** maths library using -lm. 66 */ 67 68 #define _ISOC9X_SOURCE 1 69 #define _ISOC99_SOURCE 1 70 71 #define __USE_ISOC9X 1 72 #define __USE_ISOC99 1 73 74 #include <math.h> 75 76 #elif (defined (__CYGWIN__)) 77 78 #include <math.h> 79 80 #undef HAVE_LRINT_REPLACEMENT 81 #define HAVE_LRINT_REPLACEMENT 1 82 83 #undef lrint 84 #undef lrintf 85 86 #define lrint double2int 87 #define lrintf float2int 88 89 /* 90 ** The native CYGWIN lrint and lrintf functions are buggy: 91 ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html 92 ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html 93 ** and slow. 94 ** These functions (pulled from the Public Domain MinGW math.h header) 95 ** replace the native versions. 96 */ 97 double2int(double in)98 static inline long double2int (double in) 99 { long retval ; 100 101 __asm__ __volatile__ 102 ( "fistpl %0" 103 : "=m" (retval) 104 : "t" (in) 105 : "st" 106 ) ; 107 108 return retval ; 109 } /* double2int */ 110 float2int(float in)111 static inline long float2int (float in) 112 { long retval ; 113 114 __asm__ __volatile__ 115 ( "fistpl %0" 116 : "=m" (retval) 117 : "t" (in) 118 : "st" 119 ) ; 120 121 return retval ; 122 } /* float2int */ 123 124 #elif (defined (WIN64) || defined(_WIN64)) 125 126 /* Win64 section should be places before Win32 one, because 127 ** most likely both WIN32 and WIN64 will be defined in 64-bit case. 128 */ 129 130 #include <math.h> 131 132 /* Win64 doesn't seem to have these functions, nor inline assembly. 133 ** Therefore implement inline versions of these functions here. 134 */ 135 #include <emmintrin.h> 136 #include <mmintrin.h> 137 138 __inline long int lrint(double flt)139 lrint(double flt) 140 { 141 return _mm_cvtsd_si32(_mm_load_sd(&flt)); 142 } 143 144 __inline long int lrintf(float flt)145 lrintf(float flt) 146 { 147 return _mm_cvtss_si32(_mm_load_ss(&flt)); 148 } 149 150 #elif (defined (WIN32) || defined (_WIN32)) 151 152 #undef HAVE_LRINT_REPLACEMENT 153 #define HAVE_LRINT_REPLACEMENT 1 154 155 #include <math.h> 156 157 /* 158 ** Win32 doesn't seem to have these functions. 159 ** Therefore implement inline versions of these functions here. 160 */ 161 162 __inline long int lrint(double flt)163 lrint (double flt) 164 { int intgr ; 165 166 _asm 167 { fld flt 168 fistp intgr 169 } ; 170 171 return intgr ; 172 } 173 174 __inline long int lrintf(float flt)175 lrintf (float flt) 176 { int intgr ; 177 178 _asm 179 { fld flt 180 fistp intgr 181 } ; 182 183 return intgr ; 184 } 185 186 #elif (defined (__MWERKS__) && defined (macintosh)) 187 188 /* This MacOS 9 solution was provided by Stephane Letz */ 189 190 #undef HAVE_LRINT_REPLACEMENT 191 #define HAVE_LRINT_REPLACEMENT 1 192 #include <math.h> 193 194 #undef lrint 195 #undef lrintf 196 197 #define lrint double2int 198 #define lrintf float2int 199 200 inline int float2int(register float in)201 float2int (register float in) 202 { long res [2] ; 203 204 asm 205 { fctiw in, in 206 stfd in, res 207 } 208 return res [1] ; 209 } /* float2int */ 210 211 inline int double2int(register double in)212 double2int (register double in) 213 { long res [2] ; 214 215 asm 216 { fctiw in, in 217 stfd in, res 218 } 219 return res [1] ; 220 } /* double2int */ 221 222 #elif (defined (__MACH__) && defined (__APPLE__)) 223 224 /* For Apple MacOSX. */ 225 226 #undef HAVE_LRINT_REPLACEMENT 227 #define HAVE_LRINT_REPLACEMENT 1 228 #include <math.h> 229 230 #undef lrint 231 #undef lrintf 232 233 #define lrint double2int 234 #define lrintf float2int 235 236 inline static long float2int(register float in)237 float2int (register float in) 238 { int res [2] ; 239 240 __asm__ __volatile__ 241 ( "fctiw %1, %1\n\t" 242 "stfd %1, %0" 243 : "=m" (res) /* Output */ 244 : "f" (in) /* Input */ 245 : "memory" 246 ) ; 247 248 return res [1] ; 249 } /* lrintf */ 250 251 inline static long double2int(register double in)252 double2int (register double in) 253 { int res [2] ; 254 255 __asm__ __volatile__ 256 ( "fctiw %1, %1\n\t" 257 "stfd %1, %0" 258 : "=m" (res) /* Output */ 259 : "f" (in) /* Input */ 260 : "memory" 261 ) ; 262 263 return res [1] ; 264 } /* lrint */ 265 266 #else 267 #ifndef __sgi 268 #warning "Don't have the functions lrint() and lrintf()." 269 #warning "Replacing these functions with a standard C cast." 270 #endif 271 272 #include <math.h> 273 274 #define lrint(dbl) ((long) (dbl)) 275 #define lrintf(flt) ((long) (flt)) 276 277 #endif 278 279 280 #endif /* FLOAT_CAST_HEADER */ 281 282