Annotation of embedaddon/php/Zend/zend_float.h, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | Zend Engine                                                          |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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>