Main Page
Modules
Namespaces
Classes
Files
File List
File Members
external
GeometryPredicates
include
ApproxMVBB
GeometryPredicates
xpfpa.h
Go to the documentation of this file.
1
#ifndef ApproxMVBB_GeometryPredicates_xpfpa_h
2
#define ApproxMVBB_GeometryPredicates_xpfpa_h
3
4
/* Cross Platform Floating Point Arithmetics
5
6
This header file defines several platform-dependent macros that ensure
7
equal and deterministic floating point behaviour across several platforms,
8
compilers and architectures.
9
10
The current macros are currently only used on x86 and x86_64 architectures,
11
on every other architecture, these macros expand to NOPs. This assumes that
12
other architectures do not have an internal precision and the operhand types
13
define the computational precision of floating point operations. This
14
assumption may be false, in that case, the author is interested in further
15
details on the other platform.
16
17
For further details, please visit:
18
http://www.christian-seiler.de/projekte/fpmath/
19
20
Author: Christian Seiler <webmaster@christian-seiler.de>
21
Version: 20081026
22
23
This file is released under public domain - or - in countries where this is
24
not possible under the following license:
25
26
Permission is hereby granted, free of charge, to any person obtaining a
27
copy of this software, to deal in the software without restriction,
28
including without limitation the rights to use, copy, modify, merge,
29
publish, distribute, sublicense, and/or sell copies of the software,
30
and to permit persons to whom the software is furnished to do so, subject
31
to no condition whatsoever.
32
33
This software is provided AS IS, without warranty of any kind, express or
34
implied. */
35
36
#ifndef XPFPA_H
37
#define XPFPA_H
38
39
/*
40
Implementation notes:
41
42
x86_64:
43
- Since all x86_64 compilers use SSE by default, it is probably unecessary
44
to use these macros there. We define them anyway since we are too lazy
45
to differentiate the architecture. Also, the compiler option -mfpmath=i387
46
justifies this decision.
47
48
General:
49
- It would be nice if one could detect whether SSE if used for math via some
50
funky compiler defines and if so, make the macros go to NOPs. Any ideas
51
on how to do that?
52
53
MS Visual C:
54
- Since MSVC users tipically don't use autoconf or CMake, we will detect
55
MSVC via compile time define.
56
*/
57
58
// MSVC detection (MSVC people usually don't use autoconf)
59
#ifdef _MSC_VER
60
# if _MSC_VER >= 1500
61
// Visual C++ 2008 or higher, supports _controlfp_s
62
# define HAVE__CONTROLFP_S
63
# else
64
// Visual C++ (up to 2005), supports _controlfp
65
# define HAVE__CONTROLFP
66
# endif // MSC_VER >= 1500
67
// Tell MSVC optimizer that we access FP environment
68
# pragma fenv_access (on)
69
#endif // _MSC_VER
70
71
// MSVC does NOT support precision control (_control_fp) stuff on x64 platforms!
72
// Define everything as NOP.
73
#if defined(_MSC_VER) && defined(_WIN64 )
74
75
# define XPFPA_DECLARE()
/* NOP */
76
# define XPFPA_SWITCH_DOUBLE()
/* NOP */
77
# define XPFPA_SWITCH_SINGLE()
/* NOP */
78
# define XPFPA_SWITCH_DOUBLE_EXTENDED()
/* NOP */
79
# define XPFPA_RESTORE()
/* NOP */
80
# define XPFPA_RETURN_DOUBLE(val) return (val);
81
# define XPFPA_RETURN_SINGLE(val) return (val);
82
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) return (val);
83
84
#elif HAVE__CONTROLFP_S
85
86
// float.h defines _controlfp_s
87
# include <float.h>
88
89
# define XPFPA_DECLARE() \
90
static unsigned int _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
91
92
# define XPFPA_SWITCH_DOUBLE() \
93
_controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
94
_xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
95
_controlfp_s(&_xpfpa_fpu_cw, _PC_53, _MCW_PC);
96
# define XPFPA_SWITCH_SINGLE() \
97
_controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
98
_xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
99
_controlfp_s(&_xpfpa_fpu_cw, _PC_24, _MCW_PC);
100
// NOTE: This only sets internal precision. MSVC does NOT support double-
101
// extended precision!
102
# define XPFPA_SWITCH_DOUBLE_EXTENDED() \
103
_controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
104
_xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
105
_controlfp_s(&_xpfpa_fpu_cw, _PC_64, _MCW_PC);
106
# define XPFPA_RESTORE() \
107
_controlfp_s(&_xpfpa_fpu_cw, _xpfpa_fpu_oldcw, _MCW_PC);
108
// We do NOT use the volatile return trick since _controlfp_s is a function
109
// call and thus FP registers are saved in memory anyway. However, we do use
110
// a variable to ensure that the expression passed into val will be evaluated
111
// *before* switching back contexts.
112
# define XPFPA_RETURN_DOUBLE(val) \
113
{ \
114
double _xpfpa_result = (val); \
115
XPFPA_RESTORE() \
116
return _xpfpa_result; \
117
}
118
# define XPFPA_RETURN_SINGLE(val) \
119
{ \
120
float _xpfpa_result = (val); \
121
XPFPA_RESTORE() \
122
return _xpfpa_result; \
123
}
124
// This won't work, but we add a macro for it anyway.
125
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
126
{ \
127
long double _xpfpa_result = (val); \
128
XPFPA_RESTORE() \
129
return _xpfpa_result; \
130
}
131
132
#elif defined(HAVE__CONTROLFP)
133
134
// float.h defines _controlfp
135
# include <float.h>
136
137
# define XPFPA_DECLARE() \
138
static unsigned int _xpfpa_fpu_oldcw;
139
140
# define XPFPA_SWITCH_DOUBLE() \
141
_xpfpa_fpu_oldcw = _controlfp(0, 0); \
142
_controlfp(_PC_53, _MCW_PC);
143
# define XPFPA_SWITCH_SINGLE() \
144
_xpfpa_fpu_oldcw = _controlfp(0, 0); \
145
_controlfp(_PC_24, _MCW_PC);
146
// NOTE: This will only work as expected on MinGW.
147
# define XPFPA_SWITCH_DOUBLE_EXTENDED() \
148
_xpfpa_fpu_oldcw = _controlfp(0, 0); \
149
_controlfp(_PC_64, _MCW_PC);
150
# define XPFPA_RESTORE() \
151
_controlfp(_xpfpa_fpu_oldcw, _MCW_PC);
152
// We do NOT use the volatile return trick since _controlfp is a function
153
// call and thus FP registers are saved in memory anyway. However, we do use
154
// a variable to ensure that the expression passed into val will be evaluated
155
// *before* switching back contexts.
156
# define XPFPA_RETURN_DOUBLE(val) \
157
{ \
158
double _xpfpa_result = (val); \
159
XPFPA_RESTORE() \
160
return _xpfpa_result; \
161
}
162
# define XPFPA_RETURN_SINGLE(val) \
163
{ \
164
float _xpfpa_result = (val); \
165
XPFPA_RESTORE() \
166
return _xpfpa_result; \
167
}
168
// This will only work on MinGW
169
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
170
{ \
171
long double _xpfpa_result = (val); \
172
XPFPA_RESTORE() \
173
return _xpfpa_result; \
174
}
175
176
#elif defined(HAVE__FPU_SETCW) // glibc systems
177
178
// fpu_control.h defines _FPU_[GS]ETCW
179
# include <fpu_control.h>
180
181
# define XPFPA_DECLARE() \
182
static fpu_control_t _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
183
184
# define XPFPA_SWITCH_DOUBLE() \
185
_FPU_GETCW(_xpfpa_fpu_oldcw); \
186
_xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_SINGLE) | _FPU_DOUBLE; \
187
_FPU_SETCW(_xpfpa_fpu_cw);
188
# define XPFPA_SWITCH_SINGLE() \
189
_FPU_GETCW(_xpfpa_fpu_oldcw); \
190
_xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_DOUBLE) | _FPU_SINGLE; \
191
_FPU_SETCW(_xpfpa_fpu_cw);
192
# define XPFPA_SWITCH_DOUBLE_EXTENDED() \
193
_FPU_GETCW(_xpfpa_fpu_oldcw); \
194
_xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_SINGLE & ~_FPU_DOUBLE) | _FPU_EXTENDED; \
195
_FPU_SETCW(_xpfpa_fpu_cw);
196
# define XPFPA_RESTORE() \
197
_FPU_SETCW(_xpfpa_fpu_oldcw);
198
// We use a temporary volatile variable (in a new block) in order to ensure
199
// that the optimizer does not mis-optimize the instructions. Also, a volatile
200
// variable ensures truncation to correct precision.
201
# define XPFPA_RETURN_DOUBLE(val) \
202
{ \
203
volatile double _xpfpa_result = (val); \
204
XPFPA_RESTORE() \
205
return _xpfpa_result; \
206
}
207
# define XPFPA_RETURN_SINGLE(val) \
208
{ \
209
volatile float _xpfpa_result = (val); \
210
XPFPA_RESTORE() \
211
return _xpfpa_result; \
212
}
213
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
214
{ \
215
volatile long double _xpfpa_result = (val); \
216
XPFPA_RESTORE() \
217
return _xpfpa_result; \
218
}
219
220
#elif defined(HAVE_FPSETPREC) // FreeBSD
221
222
// fpu_control.h defines _FPU_[GS]ETCW
223
# include <machine/ieeefp.h>
224
225
# define XPFPA_DECLARE() \
226
static fp_prec_t _xpfpa_fpu_oldprec;
227
228
# define XPFPA_SWITCH_DOUBLE() \
229
_xpfpa_fpu_oldprec = fpgetprec(); \
230
fpsetprec(FP_PD);
231
# define XPFPA_SWITCH_SINGLE() \
232
_xpfpa_fpu_oldprec = fpgetprec(); \
233
fpsetprec(FP_PS);
234
# define XPFPA_SWITCH_DOUBLE_EXTENDED() \
235
_xpfpa_fpu_oldprec = fpgetprec(); \
236
fpsetprec(FP_PE);
237
# define XPFPA_RESTORE() \
238
fpsetprec(_xpfpa_fpu_oldprec);
239
// We use a temporary volatile variable (in a new block) in order to ensure
240
// that the optimizer does not mis-optimize the instructions. Also, a volatile
241
// variable ensures truncation to correct precision.
242
# define XPFPA_RETURN_DOUBLE(val) \
243
{ \
244
volatile double _xpfpa_result = (val); \
245
XPFPA_RESTORE() \
246
return _xpfpa_result; \
247
}
248
# define XPFPA_RETURN_SINGLE(val) \
249
{ \
250
volatile float _xpfpa_result = (val); \
251
XPFPA_RESTORE() \
252
return _xpfpa_result; \
253
}
254
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
255
{ \
256
volatile long double _xpfpa_result = (val); \
257
XPFPA_RESTORE() \
258
return _xpfpa_result; \
259
}
260
261
#elif defined(HAVE_FPU_INLINE_ASM_X86)
262
263
/*
264
Custom x86 inline assembler implementation.
265
266
This implementation does not use predefined wrappers of the OS / compiler
267
but rather uses x86/x87 inline assembler directly. Basic instructions:
268
269
fnstcw - Store the FPU control word in a variable
270
fldcw - Load the FPU control word from a variable
271
272
Bits (only bits 8 and 9 are relevant, bits 0 to 7 are for other things):
273
0x0yy: Single precision
274
0x1yy: Reserved
275
0x2yy: Double precision
276
0x3yy: Double-extended precision
277
278
We use an unsigned int for the datatype. glibc sources add __mode__ (__HI__)
279
attribute to it (HI stands for half-integer according to docs). It is unclear
280
what the does exactly and how portable it is.
281
282
The assembly syntax works with GNU CC, Intel CC and Sun CC.
283
*/
284
285
# define XPFPA_DECLARE() \
286
static unsigned int _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
287
288
# define XPFPA_SWITCH_DOUBLE() \
289
__asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
290
_xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~0x100) | 0x200; \
291
__asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw));
292
# define XPFPA_SWITCH_SINGLE() \
293
__asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
294
_xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~0x300); \
295
__asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw));
296
# define XPFPA_SWITCH_DOUBLE_EXTENDED() \
297
__asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
298
_xpfpa_fpu_cw = _xpfpa_fpu_oldcw | 0x300; \
299
__asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw));
300
# define XPFPA_RESTORE() \
301
__asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_oldcw));
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
{ \
307
volatile double _xpfpa_result = (val); \
308
XPFPA_RESTORE() \
309
return _xpfpa_result; \
310
}
311
# define XPFPA_RETURN_SINGLE(val) \
312
{ \
313
volatile float _xpfpa_result = (val); \
314
XPFPA_RESTORE() \
315
return _xpfpa_result; \
316
}
317
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
318
{ \
319
volatile long double _xpfpa_result = (val); \
320
XPFPA_RESTORE() \
321
return _xpfpa_result; \
322
}
323
324
#else // FPU CONTROL
325
326
/*
327
This is either not an x87 FPU or the inline assembly syntax was not
328
recognized. In any case, default to NOPs for the macros and hope the
329
generated code will behave as planned.
330
*/
331
# define XPFPA_DECLARE()
/* NOP */
332
# define XPFPA_SWITCH_DOUBLE()
/* NOP */
333
# define XPFPA_SWITCH_SINGLE()
/* NOP */
334
# define XPFPA_SWITCH_DOUBLE_EXTENDED()
/* NOP */
335
# define XPFPA_RESTORE()
/* NOP */
336
# define XPFPA_RETURN_DOUBLE(val) return (val);
337
# define XPFPA_RETURN_SINGLE(val) return (val);
338
# define XPFPA_RETURN_DOUBLE_EXTENDED(val) return (val);
339
340
#endif // FPU CONTROL
341
342
#endif // XPFPA_H
343
344
#endif // header guard
asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Mon Jun 10 2019 12:38:08