blob: 77ad5b4de2fd7263e12cdecb56468436e118c5fe [file] [log] [blame]
Emeric Vigiereebea672012-08-06 17:36:30 -04001/*
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#include "config.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 config.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
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
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
139 lrint(double flt)
140 {
141 return _mm_cvtsd_si32(_mm_load_sd(&flt));
142 }
143
144 __inline long int
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
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
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
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
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
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
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