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