ref: e9f6173ed24a3af48d776d890a3f7caafd48c373
dir: /src/float_cast.h/
/* ** Copyright (c) 2001-2016, Erik de Castro Lopo <erikd@mega-nerd.com> ** All rights reserved. ** ** This code is released under 2-clause BSD license. Please see the ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING */ /* Version 1.5 */ #ifndef FLOAT_CAST_HEADER #define FLOAT_CAST_HEADER /*============================================================================ ** On Intel Pentium processors (especially PIII and probably P4), converting ** from float to int is very slow. To meet the C specs, the code produced by ** most C compilers targeting Pentium needs to change the FPU rounding mode ** before the float to int conversion is performed. ** ** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It ** is this flushing of the pipeline which is so slow. ** ** Fortunately the ISO C99 specifications define the functions lrint, lrintf, ** llrint and llrintf which fix this problem as a side effect. ** ** On Unix-like systems, the configure process should have detected the ** presence of these functions. If they weren't found we have to replace them ** here with a standard C cast. */ /* ** The C99 prototypes for lrint and lrintf are as follows: ** ** long int lrintf (float x) ; ** long int lrint (double x) ; */ #include "config.h" /* ** The presence of the required functions are detected during the configure ** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in ** the config.h file. */ #define HAVE_LRINT_REPLACEMENT 0 #if (HAVE_LRINT && HAVE_LRINTF) /* ** These defines enable functionality introduced with the 1999 ISO C ** standard. They must be defined before the inclusion of math.h to ** engage them. If optimisation is enabled, these functions will be ** inlined. With optimisation switched off, you have to link in the ** maths library using -lm. */ #define _ISOC9X_SOURCE 1 #define _ISOC99_SOURCE 1 #define __USE_ISOC9X 1 #define __USE_ISOC99 1 #include <math.h> #elif (defined (__WATCOMC__) && defined(__386__)) #include <math.h> #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int extern __inline long double2int(double); #pragma aux double2int = \ "push eax" \ "fistp dword ptr [esp]" \ "pop eax" \ parm [8087] \ value [eax] \ modify exact [eax]; extern __inline long float2int(float); #pragma aux float2int = \ "push eax" \ "fistp dword ptr [esp]" \ "pop eax" \ parm [8087] \ value [eax] \ modify exact [eax]; #elif (defined (__CYGWIN__)) #include <math.h> #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int /* ** The native CYGWIN lrint and lrintf functions are buggy: ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html ** and slow. ** These functions (pulled from the Public Domain MinGW math.h header) ** replace the native versions. */ static inline long double2int (double in) { long retval ; __asm__ __volatile__ ( "fistpl %0" : "=m" (retval) : "t" (in) : "st" ) ; return retval ; } /* double2int */ static inline long float2int (float in) { long retval ; __asm__ __volatile__ ( "fistpl %0" : "=m" (retval) : "t" (in) : "st" ) ; return retval ; } /* float2int */ #elif (defined (WIN64) || defined(_WIN64)) /* Win64 section should be places before Win32 one, because ** most likely both WIN32 and WIN64 will be defined in 64-bit case. */ #include <math.h> /* Win64 doesn't seem to have these functions, nor inline assembly. ** Therefore implement inline versions of these functions here. */ #include <emmintrin.h> #include <mmintrin.h> __inline long int lrint(double flt) { return _mm_cvtsd_si32(_mm_load_sd(&flt)); } __inline long int lrintf(float flt) { return _mm_cvtss_si32(_mm_load_ss(&flt)); } #elif (defined (WIN32) || defined (_WIN32)) #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #include <math.h> /* ** Win32 doesn't seem to have these functions. ** Therefore implement inline versions of these functions here. */ __inline long int lrint (double flt) { int intgr ; _asm { fld flt fistp intgr } ; return intgr ; } __inline long int lrintf (float flt) { int intgr ; _asm { fld flt fistp intgr } ; return intgr ; } #elif (defined (__MWERKS__) && defined (macintosh)) /* This MacOS 9 solution was provided by Stephane Letz */ #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #include <math.h> #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int inline int float2int (register float in) { long res [2] ; asm { fctiw in, in stfd in, res } return res [1] ; } /* float2int */ inline int double2int (register double in) { long res [2] ; asm { fctiw in, in stfd in, res } return res [1] ; } /* double2int */ #elif (defined (__MACH__) && defined (__APPLE__)) /* For Apple MacOSX. */ #undef HAVE_LRINT_REPLACEMENT #define HAVE_LRINT_REPLACEMENT 1 #include <math.h> #undef lrint #undef lrintf #define lrint double2int #define lrintf float2int inline static long float2int (register float in) { int res [2] ; __asm__ __volatile__ ( "fctiw %1, %1\n\t" "stfd %1, %0" : "=m" (res) /* Output */ : "f" (in) /* Input */ : "memory" ) ; return res [1] ; } /* lrintf */ inline static long double2int (register double in) { int res [2] ; __asm__ __volatile__ ( "fctiw %1, %1\n\t" "stfd %1, %0" : "=m" (res) /* Output */ : "f" (in) /* Input */ : "memory" ) ; return res [1] ; } /* lrint */ #else #ifndef __sgi #warning "Don't have the functions lrint() and lrintf()." #warning "Replacing these functions with a standard C cast." #endif #include <math.h> #define lrint(dbl) ((long) (dbl)) #define lrintf(flt) ((long) (flt)) #endif #endif /* FLOAT_CAST_HEADER */