Skip to content
Newer
Older
100644 425 lines (366 sloc) 15.3 KB
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
927bf09 @felipensp - Year++
felipensp authored
5 | Copyright (c) 1998-2011 Zend Technologies Ltd. (http://www.zend.com) |
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Christian Seiler <chris_se@gmx.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifndef ZEND_FLOAT_H
22 #define ZEND_FLOAT_H
23
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
24 /*
25 Define functions for FP initialization and de-initialization.
26 */
27 extern ZEND_API void zend_init_fpu(TSRMLS_D);
28 extern ZEND_API void zend_shutdown_fpu(TSRMLS_D);
29 extern ZEND_API void zend_ensure_fpu_mode(TSRMLS_D);
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
30
31 /* Copy of the contents of xpfpa.h (which is under public domain)
32 See http://wiki.php.net/rfc/rounding for details.
33
34 Cross Platform Floating Point Arithmetics
35
36 This header file defines several platform-dependent macros that ensure
37 equal and deterministic floating point behaviour across several platforms,
38 compilers and architectures.
39
40 The current macros are currently only used on x86 and x86_64 architectures,
41 on every other architecture, these macros expand to NOPs. This assumes that
42 other architectures do not have an internal precision and the operhand types
43 define the computational precision of floating point operations. This
44 assumption may be false, in that case, the author is interested in further
45 details on the other platform.
46
47 For further details, please visit:
48 http://www.christian-seiler.de/projekte/fpmath/
49
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
50 Version: 20090317 */
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
51
52 /*
53 Implementation notes:
54
55 x86_64:
56 - Since all x86_64 compilers use SSE by default, it is probably unecessary
57 to use these macros there. We define them anyway since we are too lazy
58 to differentiate the architecture. Also, the compiler option -mfpmath=i387
59 justifies this decision.
60
61 General:
62 - It would be nice if one could detect whether SSE if used for math via some
63 funky compiler defines and if so, make the macros go to NOPs. Any ideas
64 on how to do that?
65
66 MS Visual C:
67 - Since MSVC users tipically don't use autoconf or CMake, we will detect
68 MSVC via compile time define.
69 */
70
71 /* MSVC detection (MSVC people usually don't use autoconf) */
72 #ifdef _MSC_VER
73 # if _MSC_VER >= 1500
74 /* Visual C++ 2008 or higher, supports _controlfp_s */
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
75 # define HAVE__CONTROLFP_S
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
76 # else
77 /* Visual C++ (up to 2005), supports _controlfp */
78 # define HAVE__CONTROLFP
79 # endif /* MSC_VER >= 1500 */
80 /* Tell MSVC optimizer that we access FP environment */
1dc9e43 @pierrejoye - fix vc6 build
pierrejoye authored
81 # if _MSC_VER >= 1500
82 # pragma fenv_access (on)
83 # endif
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
84 #endif /* _MSC_VER */
85
86 #ifdef HAVE__CONTROLFP_S
87
88 /* float.h defines _controlfp_s */
89 # include <float.h>
90
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
91 # define XPFPA_HAVE_CW 1
92 # define XPFPA_CW_DATATYPE \
93 unsigned int
94
95 # define XPFPA_STORE_CW(vptr) do { \
96 _controlfp_s((unsigned int *)(vptr), 0, 0); \
97 } while (0)
98
99 # define XPFPA_RESTORE_CW(vptr) do { \
100 unsigned int _xpfpa_fpu_cw; \
101 _controlfp_s(&_xpfpa_fpu_cw, *((unsigned int *)(vptr)), _MCW_PC); \
102 } while (0)
103
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
104 # define XPFPA_DECLARE \
105 unsigned int _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
106
107 # define XPFPA_SWITCH_DOUBLE() do { \
108 _controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
109 _xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
110 _controlfp_s(&_xpfpa_fpu_cw, _PC_53, _MCW_PC); \
111 } while (0)
112 # define XPFPA_SWITCH_SINGLE() do { \
113 _controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
114 _xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
115 _controlfp_s(&_xpfpa_fpu_cw, _PC_24, _MCW_PC); \
116 } while (0)
117 /* NOTE: This only sets internal precision. MSVC does NOT support double-
118 extended precision! */
119 # define XPFPA_SWITCH_DOUBLE_EXTENDED() do { \
120 _controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
121 _xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
122 _controlfp_s(&_xpfpa_fpu_cw, _PC_64, _MCW_PC); \
123 } while (0)
124 # define XPFPA_RESTORE() \
125 _controlfp_s(&_xpfpa_fpu_cw, _xpfpa_fpu_oldcw, _MCW_PC)
126 /* We do NOT use the volatile return trick since _controlfp_s is a function
127 call and thus FP registers are saved in memory anyway. However, we do use
128 a variable to ensure that the expression passed into val will be evaluated
129 *before* switching back contexts. */
130 # define XPFPA_RETURN_DOUBLE(val) \
131 do { \
132 double _xpfpa_result = (val); \
133 XPFPA_RESTORE(); \
134 return _xpfpa_result; \
135 } while (0)
136 # define XPFPA_RETURN_SINGLE(val) \
137 do { \
138 float _xpfpa_result = (val); \
139 XPFPA_RESTORE(); \
140 return _xpfpa_result; \
141 } while (0)
142 /* This won't work, but we add a macro for it anyway. */
143 # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
144 do { \
145 long double _xpfpa_result = (val); \
146 XPFPA_RESTORE(); \
147 return _xpfpa_result; \
148 } while (0)
149
150 #elif defined(HAVE__CONTROLFP)
151
152 /* float.h defines _controlfp */
153 # include <float.h>
154
155 # define XPFPA_DECLARE \
156 unsigned int _xpfpa_fpu_oldcw;
157
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
158 # define XPFPA_HAVE_CW 1
159 # define XPFPA_CW_DATATYPE \
160 unsigned int
161
162 # define XPFPA_STORE_CW(vptr) do { \
163 *((unsigned int *)(vptr)) = _controlfp(0, 0); \
164 } while (0)
165
166 # define XPFPA_RESTORE_CW(vptr) do { \
167 _controlfp(*((unsigned int *)(vptr)), _MCW_PC); \
168 } while (0)
169
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
170 # define XPFPA_SWITCH_DOUBLE() do { \
171 _xpfpa_fpu_oldcw = _controlfp(0, 0); \
172 _controlfp(_PC_53, _MCW_PC); \
173 } while (0)
174 # define XPFPA_SWITCH_SINGLE() do { \
175 _xpfpa_fpu_oldcw = _controlfp(0, 0); \
176 _controlfp(_PC_24, _MCW_PC); \
177 } while (0)
178 /* NOTE: This will only work as expected on MinGW. */
179 # define XPFPA_SWITCH_DOUBLE_EXTENDED() do { \
180 _xpfpa_fpu_oldcw = _controlfp(0, 0); \
181 _controlfp(_PC_64, _MCW_PC); \
182 } while (0)
183 # define XPFPA_RESTORE() \
184 _controlfp(_xpfpa_fpu_oldcw, _MCW_PC)
185 /* We do NOT use the volatile return trick since _controlfp is a function
186 call and thus FP registers are saved in memory anyway. However, we do use
187 a variable to ensure that the expression passed into val will be evaluated
188 *before* switching back contexts. */
189 # define XPFPA_RETURN_DOUBLE(val) \
190 do { \
191 double _xpfpa_result = (val); \
192 XPFPA_RESTORE(); \
193 return _xpfpa_result; \
194 } while (0)
195 # define XPFPA_RETURN_SINGLE(val) \
196 do { \
197 float _xpfpa_result = (val); \
198 XPFPA_RESTORE(); \
199 return _xpfpa_result; \
200 } while (0)
201 /* This will only work on MinGW */
202 # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
203 do { \
204 long double _xpfpa_result = (val); \
205 XPFPA_RESTORE(); \
206 return _xpfpa_result; \
207 } while (0)
208
209 #elif defined(HAVE__FPU_SETCW) /* glibc systems */
210
211 /* fpu_control.h defines _FPU_[GS]ETCW */
212 # include <fpu_control.h>
213
214 # define XPFPA_DECLARE \
215 fpu_control_t _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
216
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
217 # define XPFPA_HAVE_CW 1
218 # define XPFPA_CW_DATATYPE \
219 fpu_control_t
220
221 # define XPFPA_STORE_CW(vptr) do { \
222 _FPU_GETCW((*((fpu_control_t *)(vptr)))); \
223 } while (0)
224
225 # define XPFPA_RESTORE_CW(vptr) do { \
226 _FPU_SETCW((*((fpu_control_t *)(vptr)))); \
227 } while (0)
228
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
229 # define XPFPA_SWITCH_DOUBLE() do { \
230 _FPU_GETCW(_xpfpa_fpu_oldcw); \
231 _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_SINGLE) | _FPU_DOUBLE; \
232 _FPU_SETCW(_xpfpa_fpu_cw); \
233 } while (0)
234 # define XPFPA_SWITCH_SINGLE() do { \
235 _FPU_GETCW(_xpfpa_fpu_oldcw); \
236 _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_DOUBLE) | _FPU_SINGLE; \
237 _FPU_SETCW(_xpfpa_fpu_cw); \
238 } while (0)
239 # define XPFPA_SWITCH_DOUBLE_EXTENDED() do { \
240 _FPU_GETCW(_xpfpa_fpu_oldcw); \
241 _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_SINGLE & ~_FPU_DOUBLE) | _FPU_EXTENDED; \
242 _FPU_SETCW(_xpfpa_fpu_cw); \
243 } while (0)
244 # define XPFPA_RESTORE() \
245 _FPU_SETCW(_xpfpa_fpu_oldcw)
246 /* We use a temporary volatile variable (in a new block) in order to ensure
247 that the optimizer does not mis-optimize the instructions. Also, a volatile
248 variable ensures truncation to correct precision. */
249 # define XPFPA_RETURN_DOUBLE(val) \
250 do { \
251 volatile double _xpfpa_result = (val); \
252 XPFPA_RESTORE(); \
253 return _xpfpa_result; \
254 } while (0)
255 # define XPFPA_RETURN_SINGLE(val) \
256 do { \
257 volatile float _xpfpa_result = (val); \
258 XPFPA_RESTORE(); \
259 return _xpfpa_result; \
260 } while (0)
261 # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
262 do { \
263 volatile long double _xpfpa_result = (val); \
264 XPFPA_RESTORE(); \
265 return _xpfpa_result; \
266 } while (0)
267
268 #elif defined(HAVE_FPSETPREC) /* FreeBSD */
269
270 /* fpu_control.h defines _FPU_[GS]ETCW */
271 # include <machine/ieeefp.h>
272
273 # define XPFPA_DECLARE \
274 fp_prec_t _xpfpa_fpu_oldprec;
275
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
276 # define XPFPA_HAVE_CW 1
277 # define XPFPA_CW_DATATYPE \
278 fp_prec_t
279
280 # define XPFPA_STORE_CW(vptr) do { \
281 *((fp_prec_t *)(vptr)) = fpgetprec(); \
282 } while (0)
283
284 # define XPFPA_RESTORE_CW(vptr) do { \
285 fpsetprec(*((fp_prec_t *)(vptr))); \
286 } while (0)
287
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
288 # define XPFPA_SWITCH_DOUBLE() do { \
289 _xpfpa_fpu_oldprec = fpgetprec(); \
290 fpsetprec(FP_PD); \
291 } while (0)
292 # define XPFPA_SWITCH_SINGLE() do { \
293 _xpfpa_fpu_oldprec = fpgetprec(); \
294 fpsetprec(FP_PS); \
295 } while (0)
296 # define XPFPA_SWITCH_DOUBLE_EXTENDED() do { \
297 _xpfpa_fpu_oldprec = fpgetprec(); \
298 fpsetprec(FP_PE); \
299 } while (0)
300 # define XPFPA_RESTORE() \
301 fpsetprec(_xpfpa_fpu_oldprec)
302 /* We use a temporary volatile variable (in a new block) in order to ensure
303 that the optimizer does not mis-optimize the instructions. Also, a volatile
304 variable ensures truncation to correct precision. */
305 # define XPFPA_RETURN_DOUBLE(val) \
306 do { \
307 volatile double _xpfpa_result = (val); \
308 XPFPA_RESTORE(); \
309 return _xpfpa_result; \
310 } while (0)
311 # define XPFPA_RETURN_SINGLE(val) \
312 do { \
313 volatile float _xpfpa_result = (val); \
314 XPFPA_RESTORE(); \
315 return _xpfpa_result; \
316 } while (0)
317 # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
318 do { \
319 volatile long double _xpfpa_result = (val); \
320 XPFPA_RESTORE(); \
321 return _xpfpa_result; \
322 } while (0)
323
324 #elif defined(HAVE_FPU_INLINE_ASM_X86)
325
326 /*
327 Custom x86 inline assembler implementation.
328
329 This implementation does not use predefined wrappers of the OS / compiler
330 but rather uses x86/x87 inline assembler directly. Basic instructions:
331
332 fnstcw - Store the FPU control word in a variable
333 fldcw - Load the FPU control word from a variable
334
335 Bits (only bits 8 and 9 are relevant, bits 0 to 7 are for other things):
336 0x0yy: Single precision
337 0x1yy: Reserved
338 0x2yy: Double precision
339 0x3yy: Double-extended precision
340
341 We use an unsigned int for the datatype. glibc sources add __mode__ (__HI__)
342 attribute to it (HI stands for half-integer according to docs). It is unclear
343 what the does exactly and how portable it is.
344
345 The assembly syntax works with GNU CC, Intel CC and Sun CC.
346 */
347
348 # define XPFPA_DECLARE \
349 unsigned int _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
350
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
351 # define XPFPA_HAVE_CW 1
352 # define XPFPA_CW_DATATYPE \
353 unsigned int
354
355 # define XPFPA_STORE_CW(vptr) do { \
356 __asm__ __volatile__ ("fnstcw %0" : "=m" (*((unsigned int *)(vptr)))); \
357 } while (0)
358
359 # define XPFPA_RESTORE_CW(vptr) do { \
360 __asm__ __volatile__ ("fldcw %0" : : "m" (*((unsigned int *)(vptr)))); \
361 } while (0)
362
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
363 # define XPFPA_SWITCH_DOUBLE() do { \
364 __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
365 _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~0x100) | 0x200; \
366 __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw)); \
367 } while (0)
368 # define XPFPA_SWITCH_SINGLE() do { \
369 __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
370 _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~0x300); \
371 __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw)); \
372 } while (0)
373 # define XPFPA_SWITCH_DOUBLE_EXTENDED() do { \
374 __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
375 _xpfpa_fpu_cw = _xpfpa_fpu_oldcw | 0x300; \
376 __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw)); \
377 } while (0)
378 # define XPFPA_RESTORE() \
379 __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_oldcw))
380 /* We use a temporary volatile variable (in a new block) in order to ensure
381 that the optimizer does not mis-optimize the instructions. Also, a volatile
382 variable ensures truncation to correct precision. */
383 # define XPFPA_RETURN_DOUBLE(val) \
384 do { \
385 volatile double _xpfpa_result = (val); \
386 XPFPA_RESTORE(); \
387 return _xpfpa_result; \
388 } while (0)
389 # define XPFPA_RETURN_SINGLE(val) \
390 do { \
391 volatile float _xpfpa_result = (val); \
392 XPFPA_RESTORE(); \
393 return _xpfpa_result; \
394 } while (0)
395 # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
396 do { \
397 volatile long double _xpfpa_result = (val); \
398 XPFPA_RESTORE(); \
399 return _xpfpa_result; \
400 } while (0)
401
402 #else /* FPU CONTROL */
403
404 /*
405 This is either not an x87 FPU or the inline assembly syntax was not
406 recognized. In any case, default to NOPs for the macros and hope the
407 generated code will behave as planned.
408 */
409 # define XPFPA_DECLARE /* NOP */
31c0af2 Fixed floating point mathematic speed degradation (Christian)
Dmitry Stogov authored
410 # define XPFPA_HAVE_CW 0
411 # define XPFPA_CW_DATATYPE unsigned int
412 # define XPFPA_STORE_CW(variable) /* NOP */
413 # define XPFPA_RESTORE_CW(variable) /* NOP */
04c5286 - MFH: Changed floating point behaviour to consistently use double pr…
Christian Seiler authored
414 # define XPFPA_SWITCH_DOUBLE() /* NOP */
415 # define XPFPA_SWITCH_SINGLE() /* NOP */
416 # define XPFPA_SWITCH_DOUBLE_EXTENDED() /* NOP */
417 # define XPFPA_RESTORE() /* NOP */
418 # define XPFPA_RETURN_DOUBLE(val) return (val)
419 # define XPFPA_RETURN_SINGLE(val) return (val)
420 # define XPFPA_RETURN_DOUBLE_EXTENDED(val) return (val)
421
422 #endif /* FPU CONTROL */
423
424 #endif
Something went wrong with that request. Please try again.