xpfpa.h
Go to the documentation of this file.
00001 #ifndef ApproxMVBB_GeometryPredicates_xpfpa_h
00002 #define ApproxMVBB_GeometryPredicates_xpfpa_h
00003 
00004 /* Cross Platform Floating Point Arithmetics
00005 
00006    This header file defines several platform-dependent macros that ensure
00007    equal and deterministic floating point behaviour across several platforms,
00008    compilers and architectures.
00009 
00010    The current macros are currently only used on x86 and x86_64 architectures,
00011    on every other architecture, these macros expand to NOPs. This assumes that
00012    other architectures do not have an internal precision and the operhand types
00013    define the computational precision of floating point operations. This
00014    assumption may be false, in that case, the author is interested in further
00015    details on the other platform.
00016 
00017    For further details, please visit:
00018    http://www.christian-seiler.de/projekte/fpmath/
00019 
00020    Author: Christian Seiler <webmaster@christian-seiler.de>
00021    Version: 20081026
00022 
00023    This file is released under public domain - or - in countries where this is
00024    not possible under the following license:
00025 
00026       Permission is hereby granted, free of charge, to any person obtaining a
00027       copy of this software, to deal in the software without restriction,
00028       including without limitation the rights to use, copy, modify, merge,
00029       publish, distribute, sublicense, and/or sell copies of the software,
00030       and to permit persons to whom the software is furnished to do so, subject
00031      to no condition whatsoever.
00032 
00033       This software is provided AS IS, without warranty of any kind, express or
00034       implied. */
00035 
00036 #ifndef XPFPA_H
00037 #define XPFPA_H
00038 
00039 /*
00040  Implementation notes:
00041 
00042  x86_64:
00043   - Since all x86_64 compilers use SSE by default, it is probably unecessary
00044     to use these macros there. We define them anyway since we are too lazy
00045     to differentiate the architecture. Also, the compiler option -mfpmath=i387
00046     justifies this decision.
00047 
00048  General:
00049   - It would be nice if one could detect whether SSE if used for math via some
00050     funky compiler defines and if so, make the macros go to NOPs. Any ideas
00051     on how to do that?
00052 
00053  MS Visual C:
00054   - Since MSVC users tipically don't use autoconf or CMake, we will detect
00055     MSVC via compile time define.
00056 */
00057 
00058 // MSVC detection (MSVC people usually don't use autoconf)
00059 #ifdef _MSC_VER
00060   # if _MSC_VER >= 1500
00061      // Visual C++ 2008 or higher, supports _controlfp_s
00062   #  define HAVE__CONTROLFP_S
00063   # else
00064      // Visual C++ (up to 2005), supports _controlfp
00065   #  define HAVE__CONTROLFP
00066   # endif // MSC_VER >= 1500
00067     // Tell MSVC optimizer that we access FP environment
00068   # pragma fenv_access (on)
00069 #endif // _MSC_VER
00070 
00071 // MSVC does NOT support precision control (_control_fp) stuff on x64 platforms!
00072 // Define everything as NOP.
00073 #if defined(_MSC_VER) && defined(_WIN64 )
00074 
00075   # define XPFPA_DECLARE()                    /* NOP */
00076   # define XPFPA_SWITCH_DOUBLE()              /* NOP */
00077   # define XPFPA_SWITCH_SINGLE()              /* NOP */
00078   # define XPFPA_SWITCH_DOUBLE_EXTENDED()     /* NOP */
00079   # define XPFPA_RESTORE()                    /* NOP */
00080   # define XPFPA_RETURN_DOUBLE(val)           return (val);
00081   # define XPFPA_RETURN_SINGLE(val)           return (val);
00082   # define XPFPA_RETURN_DOUBLE_EXTENDED(val)  return (val);
00083 
00084 #elif HAVE__CONTROLFP_S
00085 
00086   // float.h defines _controlfp_s
00087   # include <float.h>
00088 
00089   # define XPFPA_DECLARE() \
00090               static unsigned int _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
00091 
00092   # define XPFPA_SWITCH_DOUBLE() \
00093               _controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
00094               _xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
00095               _controlfp_s(&_xpfpa_fpu_cw, _PC_53, _MCW_PC);
00096   # define XPFPA_SWITCH_SINGLE() \
00097               _controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
00098               _xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
00099               _controlfp_s(&_xpfpa_fpu_cw, _PC_24, _MCW_PC);
00100   // NOTE: This only sets internal precision. MSVC does NOT support double-
00101   // extended precision!
00102   # define XPFPA_SWITCH_DOUBLE_EXTENDED() \
00103               _controlfp_s(&_xpfpa_fpu_cw, 0, 0); \
00104               _xpfpa_fpu_oldcw = _xpfpa_fpu_cw; \
00105               _controlfp_s(&_xpfpa_fpu_cw, _PC_64, _MCW_PC);
00106   # define XPFPA_RESTORE() \
00107               _controlfp_s(&_xpfpa_fpu_cw, _xpfpa_fpu_oldcw, _MCW_PC);
00108   // We do NOT use the volatile return trick since _controlfp_s is a function
00109   // call and thus FP registers are saved in memory anyway. However, we do use
00110   // a variable to ensure that the expression passed into val will be evaluated
00111   // *before* switching back contexts.
00112   # define XPFPA_RETURN_DOUBLE(val) \
00113               { \
00114                   double _xpfpa_result = (val); \
00115                   XPFPA_RESTORE() \
00116                   return _xpfpa_result; \
00117               }
00118   # define XPFPA_RETURN_SINGLE(val) \
00119               { \
00120                   float _xpfpa_result = (val); \
00121                   XPFPA_RESTORE() \
00122                   return _xpfpa_result; \
00123               }
00124   // This won't work, but we add a macro for it anyway.
00125   # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
00126               { \
00127                   long double _xpfpa_result = (val); \
00128                   XPFPA_RESTORE() \
00129                   return _xpfpa_result; \
00130               }
00131 
00132 #elif defined(HAVE__CONTROLFP)
00133 
00134   // float.h defines _controlfp
00135   # include <float.h>
00136 
00137   # define XPFPA_DECLARE() \
00138               static unsigned int _xpfpa_fpu_oldcw;
00139 
00140   # define XPFPA_SWITCH_DOUBLE() \
00141               _xpfpa_fpu_oldcw = _controlfp(0, 0); \
00142               _controlfp(_PC_53, _MCW_PC);
00143   # define XPFPA_SWITCH_SINGLE() \
00144               _xpfpa_fpu_oldcw = _controlfp(0, 0); \
00145               _controlfp(_PC_24, _MCW_PC);
00146   // NOTE: This will only work as expected on MinGW.
00147   # define XPFPA_SWITCH_DOUBLE_EXTENDED() \
00148               _xpfpa_fpu_oldcw = _controlfp(0, 0); \
00149               _controlfp(_PC_64, _MCW_PC);
00150   # define XPFPA_RESTORE() \
00151               _controlfp(_xpfpa_fpu_oldcw, _MCW_PC);
00152   // We do NOT use the volatile return trick since _controlfp is a function
00153   // call and thus FP registers are saved in memory anyway. However, we do use
00154   // a variable to ensure that the expression passed into val will be evaluated
00155   // *before* switching back contexts.
00156   # define XPFPA_RETURN_DOUBLE(val) \
00157               { \
00158                   double _xpfpa_result = (val); \
00159                   XPFPA_RESTORE() \
00160                   return _xpfpa_result; \
00161               }
00162   # define XPFPA_RETURN_SINGLE(val) \
00163               { \
00164                   float _xpfpa_result = (val); \
00165                   XPFPA_RESTORE() \
00166                   return _xpfpa_result; \
00167               }
00168   // This will only work on MinGW
00169   # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
00170               { \
00171                   long double _xpfpa_result = (val); \
00172                   XPFPA_RESTORE() \
00173                   return _xpfpa_result; \
00174               }
00175 
00176 #elif defined(HAVE__FPU_SETCW) // glibc systems
00177 
00178   // fpu_control.h defines _FPU_[GS]ETCW
00179   # include <fpu_control.h>
00180 
00181   # define XPFPA_DECLARE() \
00182               static fpu_control_t _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
00183 
00184   # define XPFPA_SWITCH_DOUBLE() \
00185               _FPU_GETCW(_xpfpa_fpu_oldcw); \
00186               _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_SINGLE) | _FPU_DOUBLE; \
00187               _FPU_SETCW(_xpfpa_fpu_cw);
00188   # define XPFPA_SWITCH_SINGLE() \
00189               _FPU_GETCW(_xpfpa_fpu_oldcw); \
00190               _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_DOUBLE) | _FPU_SINGLE; \
00191               _FPU_SETCW(_xpfpa_fpu_cw);
00192   # define XPFPA_SWITCH_DOUBLE_EXTENDED() \
00193               _FPU_GETCW(_xpfpa_fpu_oldcw); \
00194               _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~_FPU_SINGLE & ~_FPU_DOUBLE) | _FPU_EXTENDED; \
00195               _FPU_SETCW(_xpfpa_fpu_cw);
00196   # define XPFPA_RESTORE() \
00197               _FPU_SETCW(_xpfpa_fpu_oldcw);
00198   // We use a temporary volatile variable (in a new block) in order to ensure
00199   // that the optimizer does not mis-optimize the instructions. Also, a volatile
00200   // variable ensures truncation to correct precision.
00201   # define XPFPA_RETURN_DOUBLE(val) \
00202               { \
00203                   volatile double _xpfpa_result = (val); \
00204                   XPFPA_RESTORE() \
00205                   return _xpfpa_result; \
00206               }
00207   # define XPFPA_RETURN_SINGLE(val) \
00208               { \
00209                   volatile float _xpfpa_result = (val); \
00210                   XPFPA_RESTORE() \
00211                   return _xpfpa_result; \
00212               }
00213   # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
00214               { \
00215                   volatile long double _xpfpa_result = (val); \
00216                   XPFPA_RESTORE() \
00217                   return _xpfpa_result; \
00218               }
00219 
00220 #elif defined(HAVE_FPSETPREC) // FreeBSD
00221 
00222   // fpu_control.h defines _FPU_[GS]ETCW
00223   # include <machine/ieeefp.h>
00224 
00225   # define XPFPA_DECLARE() \
00226               static fp_prec_t _xpfpa_fpu_oldprec;
00227 
00228   # define XPFPA_SWITCH_DOUBLE() \
00229               _xpfpa_fpu_oldprec = fpgetprec(); \
00230               fpsetprec(FP_PD);
00231   # define XPFPA_SWITCH_SINGLE() \
00232               _xpfpa_fpu_oldprec = fpgetprec(); \
00233               fpsetprec(FP_PS);
00234   # define XPFPA_SWITCH_DOUBLE_EXTENDED() \
00235               _xpfpa_fpu_oldprec = fpgetprec(); \
00236               fpsetprec(FP_PE);
00237   # define XPFPA_RESTORE() \
00238               fpsetprec(_xpfpa_fpu_oldprec);
00239   // We use a temporary volatile variable (in a new block) in order to ensure
00240   // that the optimizer does not mis-optimize the instructions. Also, a volatile
00241   // variable ensures truncation to correct precision.
00242   # define XPFPA_RETURN_DOUBLE(val) \
00243               { \
00244                   volatile double _xpfpa_result = (val); \
00245                   XPFPA_RESTORE() \
00246                   return _xpfpa_result; \
00247               }
00248   # define XPFPA_RETURN_SINGLE(val) \
00249               { \
00250                   volatile float _xpfpa_result = (val); \
00251                   XPFPA_RESTORE() \
00252                   return _xpfpa_result; \
00253               }
00254   # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
00255               { \
00256                   volatile long double _xpfpa_result = (val); \
00257                   XPFPA_RESTORE() \
00258                   return _xpfpa_result; \
00259               }
00260 
00261 #elif defined(HAVE_FPU_INLINE_ASM_X86)
00262 
00263   /*
00264     Custom x86 inline assembler implementation.
00265 
00266     This implementation does not use predefined wrappers of the OS / compiler
00267     but rather uses x86/x87 inline assembler directly. Basic instructions:
00268 
00269     fnstcw - Store the FPU control word in a variable
00270     fldcw  - Load the FPU control word from a variable
00271 
00272     Bits (only bits 8 and 9 are relevant, bits 0 to 7 are for other things):
00273        0x0yy: Single precision
00274        0x1yy: Reserved
00275        0x2yy: Double precision
00276        0x3yy: Double-extended precision
00277 
00278     We use an unsigned int for the datatype. glibc sources add __mode__ (__HI__)
00279     attribute to it (HI stands for half-integer according to docs). It is unclear
00280     what the does exactly and how portable it is.
00281 
00282     The assembly syntax works with GNU CC, Intel CC and Sun CC.
00283   */
00284 
00285   # define XPFPA_DECLARE() \
00286               static unsigned int _xpfpa_fpu_oldcw, _xpfpa_fpu_cw;
00287 
00288   # define XPFPA_SWITCH_DOUBLE() \
00289               __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
00290               _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~0x100) | 0x200; \
00291               __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw));
00292   # define XPFPA_SWITCH_SINGLE() \
00293               __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
00294               _xpfpa_fpu_cw = (_xpfpa_fpu_oldcw & ~0x300); \
00295               __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw));
00296   # define XPFPA_SWITCH_DOUBLE_EXTENDED() \
00297               __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_xpfpa_fpu_oldcw)); \
00298               _xpfpa_fpu_cw = _xpfpa_fpu_oldcw | 0x300; \
00299               __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_cw));
00300   # define XPFPA_RESTORE() \
00301               __asm__ __volatile__ ("fldcw %0" : : "m" (*&_xpfpa_fpu_oldcw));
00302   // We use a temporary volatile variable (in a new block) in order to ensure
00303   // that the optimizer does not mis-optimize the instructions. Also, a volatile
00304   // variable ensures truncation to correct precision.
00305   # define XPFPA_RETURN_DOUBLE(val) \
00306               { \
00307                   volatile double _xpfpa_result = (val); \
00308                   XPFPA_RESTORE() \
00309                   return _xpfpa_result; \
00310               }
00311   # define XPFPA_RETURN_SINGLE(val) \
00312               { \
00313                   volatile float _xpfpa_result = (val); \
00314                   XPFPA_RESTORE() \
00315                   return _xpfpa_result; \
00316               }
00317   # define XPFPA_RETURN_DOUBLE_EXTENDED(val) \
00318               { \
00319                   volatile long double _xpfpa_result = (val); \
00320                   XPFPA_RESTORE() \
00321                   return _xpfpa_result; \
00322               }
00323 
00324 #else // FPU CONTROL
00325 
00326   /*
00327     This is either not an x87 FPU or the inline assembly syntax was not
00328     recognized. In any case, default to NOPs for the macros and hope the
00329     generated code will behave as planned.
00330   */
00331   # define XPFPA_DECLARE()                    /* NOP */
00332   # define XPFPA_SWITCH_DOUBLE()              /* NOP */
00333   # define XPFPA_SWITCH_SINGLE()              /* NOP */
00334   # define XPFPA_SWITCH_DOUBLE_EXTENDED()     /* NOP */
00335   # define XPFPA_RESTORE()                    /* NOP */
00336   # define XPFPA_RETURN_DOUBLE(val)           return (val);
00337   # define XPFPA_RETURN_SINGLE(val)           return (val);
00338   # define XPFPA_RETURN_DOUBLE_EXTENDED(val)  return (val);
00339 
00340 #endif // FPU CONTROL
00341 
00342 #endif // XPFPA_H
00343 
00344 #endif // header guard 


asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Sat Jun 8 2019 20:21:50