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