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