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 #ifdef _MSC_VER
153 	__inline long int
154 	lrint (double flt)
155 	{	int intgr ;
156 
157 		_asm
158 		{	fld flt
159 			fistp intgr
160 			} ;
161 
162 		return intgr ;
163 	}
164 
165 	__inline long int
166 	lrintf (float flt)
167 	{	int intgr ;
168 
169 		_asm
170 		{	fld flt
171 			fistp intgr
172 			} ;
173 
174 		return intgr ;
175 	}
176 #endif
177 
178 #elif (defined (__MWERKS__) && defined (macintosh))
179 
180 	/* This MacOS 9 solution was provided by Stephane Letz */
181 
182 	#undef		HAVE_LRINT_REPLACEMENT
183 	#define		HAVE_LRINT_REPLACEMENT	1
184 	#include	<math.h>
185 
186 	#undef	lrint
187 	#undef	lrintf
188 
189 	#define	lrint	double2int
190 	#define	lrintf	float2int
191 
192 	inline int
193 	float2int (register float in)
194 	{	long res [2] ;
195 
196 		asm
197 		{	fctiw	in, in
198 			stfd	 in, res
199 		}
200 		return res [1] ;
201 	} /* float2int */
202 
203 	inline int
204 	double2int (register double in)
205 	{	long res [2] ;
206 
207 		asm
208 		{	fctiw	in, in
209 			stfd	 in, res
210 		}
211 		return res [1] ;
212 	} /* double2int */
213 
214 #elif (defined (__MACH__) && defined (__APPLE__))
215 
216 	/* For Apple MacOSX. */
217 
218 	#undef		HAVE_LRINT_REPLACEMENT
219 	#define		HAVE_LRINT_REPLACEMENT	1
220 	#include	<math.h>
221 
222 	#undef lrint
223 	#undef lrintf
224 
225 	#define lrint	double2int
226 	#define lrintf	float2int
227 
228 	inline static long
229 	float2int (register float in)
230 	{	int res [2] ;
231 
232 		__asm__ __volatile__
233 		(	"fctiw	%1, %1\n\t"
234 			"stfd	%1, %0"
235 			: "=m" (res)	/* Output */
236 			: "f" (in)		/* Input */
237 			: "memory"
238 			) ;
239 
240 		return res [1] ;
241 	} /* lrintf */
242 
243 	inline static long
244 	double2int (register double in)
245 	{	int res [2] ;
246 
247 		__asm__ __volatile__
248 		(	"fctiw	%1, %1\n\t"
249 			"stfd	%1, %0"
250 			: "=m" (res)	/* Output */
251 			: "f" (in)		/* Input */
252 			: "memory"
253 			) ;
254 
255 		return res [1] ;
256 	} /* lrint */
257 
258 #else
259 	#ifndef __sgi
260 	#warning "Don't have the functions lrint() and lrintf()."
261 	#warning "Replacing these functions with a standard C cast."
262 	#endif
263 
264 	#include	<math.h>
265 
266 	#define	lrint(dbl)		((long) (dbl))
267 	#define	lrintf(flt)		((long) (flt))
268 
269 #endif
270 
271 
272 #endif /* FLOAT_CAST_HEADER */
273 
274