this repo has no description
at fixPythonPipStalling 384 lines 15 kB view raw
1/* 2 * fenv.c 3 * xmmLibm 4 * 5 * Created by iano on 6/21/05. 6 * Copyright 2005 __MyCompanyName__. All rights reserved. 7 * 8 */ 9 10#include "xmmLibm_prefix.h" 11 12#include "fenv.h" 13#include <xmmintrin.h> 14 15#define DEFAULT_CONTROL 0x037f 16#define DEFAULT_STATUS 0x0 17#define DEFAULT_RESERVED "\0\0\0\0\0\0\0" 18 19#define GET_FSW() ({ unsigned short _result; asm volatile ("fnstsw %0" : "=m" (_result)::"memory"); /*return*/ _result; }) 20#define GET_FCW() ({ unsigned short _result; asm volatile ("fnstcw %0" : "=m" (_result)::"memory"); /*return*/ _result; }) 21#define SET_FCW(_a) { unsigned short _aa = _a; asm volatile ("fldcw %0" : :"m" (_aa)); } 22 23typedef struct { 24 unsigned short __control; 25 unsigned short __reserved1; 26 unsigned short __status; 27 unsigned short __reserved2; 28 unsigned int __private3; 29 unsigned int __private4; 30 unsigned int __private5; 31 unsigned int __private6; 32 unsigned int __private7; 33} __fpustate_t; 34 35#define FE_ALL_RND ( FE_TONEAREST | FE_TOWARDZERO | FE_UPWARD | FE_DOWNWARD ) 36 37static inline int _fesetexceptflag(const fexcept_t *flagp, int excepts ) ALWAYS_INLINE; 38static inline int _fesetexceptflag(const fexcept_t *flagp, int excepts ) 39{ 40 int state; 41 __fpustate_t currfpu; 42 unsigned int mxcsr; 43 unsigned int exceptMask = excepts & FE_ALL_EXCEPT; 44 unsigned int andMask = ~exceptMask; // clear just the bits indicated 45 unsigned int orMask = *flagp & exceptMask; // latch the specified bits 46 47 //read the state 48 mxcsr = _mm_getcsr(); //read the MXCSR state 49 asm volatile ("fnstenv %0" : "=m" (currfpu) ); //read x87 state 50 51 //fix up the MXCSR state 52 mxcsr &= andMask; 53 mxcsr |= orMask; 54 55 //fix up the x87 state 56 state = currfpu.__status; 57 state &= andMask; 58 state |= orMask; 59 currfpu.__status = state; 60 61 //store the state 62 asm volatile ("ldmxcsr %0 ; fldenv %1" : : "m" (mxcsr), "m" (currfpu)); 63 return 0; 64} 65 66static inline int _fegetexceptflag(fexcept_t *flagp, int excepts); 67static inline int _fegetexceptflag(fexcept_t *flagp, int excepts) 68{ 69 fexcept_t fsw = GET_FSW(); //get the x87 status word 70 unsigned int mxcsr = _mm_getcsr(); //get the mxcsr 71 fexcept_t result = mxcsr | fsw; 72 73 result &= excepts & FE_ALL_EXCEPT; 74 75 *flagp = result; 76 return 0; 77} 78 79 80#if defined( BUILDING_FOR_CARBONCORE_LEGACY ) || defined(DARLING) 81 82const fenv_t _FE_DFL_ENV = { DEFAULT_CONTROL, 83 DEFAULT_STATUS, 84 DEFAULT_MXCSR, 85 DEFAULT_RESERVED}; 86 87const fenv_t _FE_DFL_DISABLE_SSE_DENORMS_ENV = { DEFAULT_CONTROL, 88 DEFAULT_STATUS, 89 DEFAULT_MXCSR | 0x8040, 90 DEFAULT_RESERVED }; 91 92 93/******************************************************************************* 94* The function "feclearexcept" clears the supported floating point * 95* exceptions represented by its argument. * 96*******************************************************************************/ 97 98int feclearexcept(int excepts) 99{ 100 fexcept_t zero = 0; 101 return _fesetexceptflag( &zero, excepts ); 102} 103 104 105 106/******************************************************************************* 107* The function "feraiseexcept" raises the supported floating-point * 108* exceptions represented by its argument. The order in which these * 109* floating-point exceptions are raised is unspecified. * 110*******************************************************************************/ 111 112int feraiseexcept(int excepts) 113{ 114 fexcept_t t = excepts; 115 116 int err = _fesetexceptflag ( &t, excepts ); 117 asm volatile ("fwait" :"=X" (t)::"memory"); // and raise the exception(s) 118 return err; 119} 120 121 122 123 124 125 126/******************************************************************************* 127* The function "fetestexcept" determines which of the specified subset of * 128* the floating-point exception flags are currently set. The excepts * 129* argument specifies the floating-point status flags to be queried. This * 130* function returns the value of the bitwise OR of the floating-point * 131* exception macros corresponding to the currently set floating-point * 132* exceptions included in excepts. * 133* * 134* On MacOS X for Intel, the result is the value of union of the * 135* corresponding result from the x87 and SSE floating point states. * 136*******************************************************************************/ 137 138int fetestexcept(int excepts ) 139{ 140 fexcept_t fsw = GET_FSW(); //get the x87 status word 141 unsigned int mxcsr = _mm_getcsr(); //get the mxcsr 142 unsigned int exceptMask = excepts & FE_ALL_EXCEPT; 143 144 mxcsr |= fsw; 145 mxcsr &= exceptMask; 146 147 return mxcsr; 148} 149 150 151/******************************************************************************* 152* The following functions provide control of rounding direction modes. * 153*******************************************************************************/ 154 155/******************************************************************************* 156* The function "fegetround" returns the value of the rounding direction * 157* macro which represents the current rounding direction, or a negative * 158* if there is no such rounding direction macro or the current rounding * 159* direction is not determinable. * 160*******************************************************************************/ 161 162int fegetround(void) 163{ 164 int fcw = GET_FCW(); 165 166 return (fcw & FE_ALL_RND); 167} 168 169 170/******************************************************************************* 171* The function "fesetround" establishes the rounding direction represented * 172* by its argument "round". If the argument is not equal to the value of a * 173* rounding direction macro, the rounding direction is not changed. It * 174* returns zero if and only if the argument is equal to a rounding * 175* direction macro. * 176*******************************************************************************/ 177 178int fesetround(int round ) 179{ 180 if ((round & ~FE_ALL_RND)) 181 return 1; 182 else 183 { 184 unsigned short fcw = GET_FCW(); 185 int mxcsr = _mm_getcsr(); 186 187 fcw &= ~FE_ALL_RND; 188 fcw |= round; 189 mxcsr &= ~( FE_ALL_RND << 3 ); 190 mxcsr |= round << 3; 191 192 _mm_setcsr( mxcsr ); 193 SET_FCW( fcw ); 194 195 return 0; 196 } 197} 198 199 200/******************************************************************************* 201* The following functions manage the floating-point environment, exception * 202* flags and dynamic modes, as one entity. * 203*******************************************************************************/ 204 205/******************************************************************************* 206* The fegetenv function stores the current floating-point enviornment in * 207* the object pointed to by envp. * 208*******************************************************************************/ 209int fegetenv(fenv_t *envp) 210{ 211 __fpustate_t currfpu; 212 int mxcsr = _mm_getcsr(); 213 214 asm volatile ("fnstenv %0" : "=m" (currfpu) :: "memory"); 215 216 envp->__control = currfpu.__control; 217 envp->__status = currfpu.__status; 218 envp->__mxcsr = mxcsr; 219 ((int*) envp->__reserved)[0] = 0; 220 ((int*) envp->__reserved)[1] = 0; 221 222 // fnstenv masks floating-point exceptions. We restore the state here 223 // in case any exceptions were originally unmasked. 224 asm volatile ("fldenv %0" : : "m" (currfpu)); 225 226 return 0; 227} 228 229/******************************************************************************* 230* The feholdexcept function saves the current floating-point environment in * 231* the object pointed to by envp, clears the floating-point status flags, * 232* and then installs a non-stop (continue on floating-point exceptions) * 233* mode, if available, for all floating-point exceptions. The feholdexcept * 234* function returns zero if and only if non-stop floating-point exceptions * 235* handling was successfully installed. * 236*******************************************************************************/ 237int feholdexcept(fenv_t *envp) 238{ 239 __fpustate_t currfpu; 240 int mxcsr; 241 242 mxcsr = _mm_getcsr(); 243 asm volatile ("fnstenv %0" : "=m" (*&currfpu) :: "memory"); 244 245 envp->__control = currfpu.__control; 246 envp->__status = currfpu.__status; 247 envp->__mxcsr = mxcsr; 248 ((int*) envp->__reserved)[0] = 0; 249 ((int*) envp->__reserved)[1] = 0; 250 251 currfpu.__control |= FE_ALL_EXCEPT; // FPU shall handle all exceptions 252 currfpu.__status &= ~FE_ALL_EXCEPT; 253 mxcsr |= FE_ALL_EXCEPT << 7; // left shifted because control mask is <<7 of the flags 254 mxcsr &= ~FE_ALL_EXCEPT; 255 256 asm volatile ("ldmxcsr %0 ; fldenv %1" : : "m" (*&mxcsr), "m" (*&currfpu)); 257 258 return 0; 259} 260 261#define MXCSR_PLUS_FZ_DAZ ( DEFAULT_MXCSR | 0x8040 ) 262 263 264/******************************************************************************* 265* The fesetnv function establishes the floating-point environment * 266* represented by the object pointed to by envp. The argument envp shall * 267* point to an object set by a call to fegetenv or feholdexcept, or equal to * 268* a floating-point environment macro -- we define only *FE_DFL_ENV and * 269* FE_DISABLE_SSE_DENORMS_ENV -- to be C99 standard compliant and portable * 270* to other architectures. Note that fesetnv merely installs the state of * 271* the floating-point status flags represented through its argument, and * 272* does not raise these floating-point exceptions. * 273* * 274* On MacOS X for Intel you may test and set the bits in *envp yourself, * 275* provided that you conditionalize the code appropriately to preserve * 276* portability and you follow the various strictures and suggestions * 277* provided by Intel in appropriate processor documentation. Please be aware * 278* that because there are two hardware locations for setting and reading * 279* floating point environment, this function (and others like it) are not * 280* atomic -- that is, for a brief period of time during the function call * 281* your new environment will have been applied to one but not both of the * 282* floating point engines (x87 and SSE). In addition, the behavior of some * 283* higher level interfaces (fegetround) is undefined if the x87 and SSE * 284* floating point units rounding modes are configured differently. Please * 285* use common sense. * 286*******************************************************************************/ 287int fesetenv(const fenv_t *envp) 288{ 289 __fpustate_t currfpu; 290 asm volatile ("fnstenv %0" : "=m" (currfpu)); 291 292 currfpu.__control = envp->__control; 293 currfpu.__status = envp->__status; 294 295 asm volatile ("ldmxcsr %0 ; fldenv %1" : : "m" (envp->__mxcsr), "m" (currfpu)); 296 return 0; 297} 298 299 300 301/******************************************************************************* 302* The feupdateenv function saves the currently raised floating-point * 303* exceptions in its automatic storage, installs the floating-point * 304* environment represented by the object pointed to by envp, and then raises * 305* the saved floating-point exceptions. The argument envp shall point to an * 306* object set by a call to feholdexcept or fegetenv or equal a * 307* floating-point environment macro. * 308* * 309* Please see the description of feholdexcept for additional ways to create * 310* a fenv_t object, which are valid only for MacOS X for Intel. * 311*******************************************************************************/ 312int feupdateenv(const fenv_t *envp) 313{ 314 __fpustate_t currfpu; 315 asm volatile ("fnstenv %0" : "=m" (currfpu)); 316 317 currfpu.__control = envp->__control; 318 currfpu.__status = envp->__status; 319 320 asm volatile ("ldmxcsr %0 ; fldenv %1; fwait " : : "m" (envp->__mxcsr), "m" (currfpu)); 321 return 0; 322} 323 324/* Legacy entry point */ 325void fegetexcept ( fexcept_t *flagp, int excepts ) 326{ 327 _fegetexceptflag (flagp, excepts ); 328} 329 330/* Legacy entry point */ 331void fesetexcept ( fexcept_t *flagp, int excepts ) 332{ 333 _fesetexceptflag ( flagp, excepts ); 334} 335 336#else 337 338/******************************************************************************* 339* The function "fegetexceptflag" stores a implementation-defined * 340* representation of the states of the floating-point status flags indicated * 341* by its integer argument excepts in the object pointed to by the argument, * 342* flagp. * 343*******************************************************************************/ 344 345int fegetexceptflag(fexcept_t *flagp, int excepts) 346{ 347 return _fegetexceptflag( flagp, excepts ); 348} 349 350/******************************************************************************* 351* The function "fesetexceptflag" sets or clears the floating point status * 352* flags indicated by the argument excepts to the states stored in the * 353* object pointed to by flagp. The value of the *flagp shall have been set * 354* by a previous call to fegetexceptflag whose second argument represented * 355* at least those floating-point exceptions represented by the argument * 356* excepts. This function does not raise floating-point exceptions; it just * 357* sets the state of the flags. * 358*******************************************************************************/ 359 360int fesetexceptflag(const fexcept_t *flagp, int excepts ) 361{ 362 return _fesetexceptflag( flagp, excepts ); 363} 364 365int __fegetfltrounds( void ); 366int __fegetfltrounds( void ) 367{ 368 switch ( fegetround() ) 369 { 370 case FE_TONEAREST: 371 return 1; 372 case FE_TOWARDZERO: 373 return 0; 374 case FE_UPWARD: 375 return 2; 376 case FE_DOWNWARD: 377 return 3; 378 default: 379 return -1; 380 } 381} 382 383#endif 384