You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
5.4KB

  1. /*
  2. ** Copyright (c) 2001-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
  3. ** All rights reserved.
  4. **
  5. ** This code is released under 2-clause BSD license. Please see the
  6. ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
  7. */
  8. /* Version 1.5 */
  9. #ifndef FLOAT_CAST_HEADER
  10. #define FLOAT_CAST_HEADER
  11. /*============================================================================
  12. ** On Intel Pentium processors (especially PIII and probably P4), converting
  13. ** from float to int is very slow. To meet the C specs, the code produced by
  14. ** most C compilers targeting Pentium needs to change the FPU rounding mode
  15. ** before the float to int conversion is performed.
  16. **
  17. ** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
  18. ** is this flushing of the pipeline which is so slow.
  19. **
  20. ** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
  21. ** llrint and llrintf which fix this problem as a side effect.
  22. **
  23. ** On Unix-like systems, the configure process should have detected the
  24. ** presence of these functions. If they weren't found we have to replace them
  25. ** here with a standard C cast.
  26. */
  27. /*
  28. ** The C99 prototypes for lrint and lrintf are as follows:
  29. **
  30. ** long int lrintf (float x) ;
  31. ** long int lrint (double x) ;
  32. */
  33. #include "config.h"
  34. /*
  35. ** The presence of the required functions are detected during the configure
  36. ** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
  37. ** the config.h file.
  38. */
  39. #define HAVE_LRINT_REPLACEMENT 0
  40. #if (HAVE_LRINT && HAVE_LRINTF)
  41. /*
  42. ** These defines enable functionality introduced with the 1999 ISO C
  43. ** standard. They must be defined before the inclusion of math.h to
  44. ** engage them. If optimisation is enabled, these functions will be
  45. ** inlined. With optimisation switched off, you have to link in the
  46. ** maths library using -lm.
  47. */
  48. #define _ISOC9X_SOURCE 1
  49. #define _ISOC99_SOURCE 1
  50. #define __USE_ISOC9X 1
  51. #define __USE_ISOC99 1
  52. #include <math.h>
  53. #elif (defined (__CYGWIN__))
  54. #include <math.h>
  55. #undef HAVE_LRINT_REPLACEMENT
  56. #define HAVE_LRINT_REPLACEMENT 1
  57. #undef lrint
  58. #undef lrintf
  59. #define lrint double2int
  60. #define lrintf float2int
  61. /*
  62. ** The native CYGWIN lrint and lrintf functions are buggy:
  63. ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html
  64. ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html
  65. ** and slow.
  66. ** These functions (pulled from the Public Domain MinGW math.h header)
  67. ** replace the native versions.
  68. */
  69. static inline long double2int (double in)
  70. { long retval ;
  71. __asm__ __volatile__
  72. ( "fistpl %0"
  73. : "=m" (retval)
  74. : "t" (in)
  75. : "st"
  76. ) ;
  77. return retval ;
  78. } /* double2int */
  79. static inline long float2int (float in)
  80. { long retval ;
  81. __asm__ __volatile__
  82. ( "fistpl %0"
  83. : "=m" (retval)
  84. : "t" (in)
  85. : "st"
  86. ) ;
  87. return retval ;
  88. } /* float2int */
  89. #elif (defined (WIN64) || defined(_WIN64))
  90. /* Win64 section should be places before Win32 one, because
  91. ** most likely both WIN32 and WIN64 will be defined in 64-bit case.
  92. */
  93. #include <math.h>
  94. /* Win64 doesn't seem to have these functions, nor inline assembly.
  95. ** Therefore implement inline versions of these functions here.
  96. */
  97. #include <emmintrin.h>
  98. #include <mmintrin.h>
  99. __inline long int
  100. lrint(double flt)
  101. {
  102. return _mm_cvtsd_si32(_mm_load_sd(&flt));
  103. }
  104. __inline long int
  105. lrintf(float flt)
  106. {
  107. return _mm_cvtss_si32(_mm_load_ss(&flt));
  108. }
  109. #elif (defined (WIN32) || defined (_WIN32))
  110. #undef HAVE_LRINT_REPLACEMENT
  111. #define HAVE_LRINT_REPLACEMENT 1
  112. #include <math.h>
  113. /*
  114. ** Win32 doesn't seem to have these functions.
  115. ** Therefore implement inline versions of these functions here.
  116. */
  117. __inline long int
  118. lrint (double flt)
  119. { int intgr ;
  120. _asm
  121. { fld flt
  122. fistp intgr
  123. } ;
  124. return intgr ;
  125. }
  126. __inline long int
  127. lrintf (float flt)
  128. { int intgr ;
  129. _asm
  130. { fld flt
  131. fistp intgr
  132. } ;
  133. return intgr ;
  134. }
  135. #elif (defined (__MWERKS__) && defined (macintosh))
  136. /* This MacOS 9 solution was provided by Stephane Letz */
  137. #undef HAVE_LRINT_REPLACEMENT
  138. #define HAVE_LRINT_REPLACEMENT 1
  139. #include <math.h>
  140. #undef lrint
  141. #undef lrintf
  142. #define lrint double2int
  143. #define lrintf float2int
  144. inline int
  145. float2int (register float in)
  146. { long res [2] ;
  147. asm
  148. { fctiw in, in
  149. stfd in, res
  150. }
  151. return res [1] ;
  152. } /* float2int */
  153. inline int
  154. double2int (register double in)
  155. { long res [2] ;
  156. asm
  157. { fctiw in, in
  158. stfd in, res
  159. }
  160. return res [1] ;
  161. } /* double2int */
  162. #elif (defined (__MACH__) && defined (__APPLE__))
  163. /* For Apple MacOSX. */
  164. #undef HAVE_LRINT_REPLACEMENT
  165. #define HAVE_LRINT_REPLACEMENT 1
  166. #include <math.h>
  167. #undef lrint
  168. #undef lrintf
  169. #define lrint double2int
  170. #define lrintf float2int
  171. inline static long
  172. float2int (register float in)
  173. { int res [2] ;
  174. __asm__ __volatile__
  175. ( "fctiw %1, %1\n\t"
  176. "stfd %1, %0"
  177. : "=m" (res) /* Output */
  178. : "f" (in) /* Input */
  179. : "memory"
  180. ) ;
  181. return res [1] ;
  182. } /* lrintf */
  183. inline static long
  184. double2int (register double in)
  185. { int res [2] ;
  186. __asm__ __volatile__
  187. ( "fctiw %1, %1\n\t"
  188. "stfd %1, %0"
  189. : "=m" (res) /* Output */
  190. : "f" (in) /* Input */
  191. : "memory"
  192. ) ;
  193. return res [1] ;
  194. } /* lrint */
  195. #else
  196. #ifndef __sgi
  197. #warning "Don't have the functions lrint() and lrintf()."
  198. #warning "Replacing these functions with a standard C cast."
  199. #endif
  200. #include <math.h>
  201. #define lrint(dbl) ((long) (dbl))
  202. #define lrintf(flt) ((long) (flt))
  203. #endif
  204. #endif /* FLOAT_CAST_HEADER */