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>