Annotation of embedaddon/php/Zend/zend_float.h, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | Zend Engine |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
! 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: zend_float.h 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: #ifndef ZEND_FLOAT_H
! 22: #define ZEND_FLOAT_H
! 23:
! 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);
! 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:
! 50: Version: 20090317 */
! 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 */
! 75: # define HAVE__CONTROLFP_S
! 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 */
! 81: # if _MSC_VER >= 1500
! 82: # pragma fenv_access (on)
! 83: # endif
! 84: #endif /* _MSC_VER */
! 85:
! 86: #ifdef HAVE__CONTROLFP_S
! 87:
! 88: /* float.h defines _controlfp_s */
! 89: # include <float.h>
! 90:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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:
! 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 */
! 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 */
! 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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>