1 /*
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 // MEANX #include "xonfig.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 xonfig.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 
double2int(double in)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 
float2int(float in)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
lrint(double flt)139 	lrint(double flt)
140 	{
141 		return _mm_cvtsd_si32(_mm_load_sd(&flt));
142 	}
143 
144 	__inline long int
lrintf(float flt)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
lrint(double flt)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
lrintf(float flt)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
float2int(register float in)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
double2int(register double in)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
float2int(register float in)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
double2int(register double in)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 
282