File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / Zend / zend_float.h
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:04:03 2014 UTC (10 years, 4 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | Zend Engine                                                          |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1998-2014 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,v 1.1.1.4 2014/06/15 20:04:03 misho Exp $ */
   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>