|
Packit |
8dc392 |
///////////////////////////////////////////////////////////////////////////
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Copyright (c) 1997, Industrial Light & Magic, a division of Lucas
|
|
Packit |
8dc392 |
// Digital Ltd. LLC
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// All rights reserved.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Redistribution and use in source and binary forms, with or without
|
|
Packit |
8dc392 |
// modification, are permitted provided that the following conditions are
|
|
Packit |
8dc392 |
// met:
|
|
Packit |
8dc392 |
// * Redistributions of source code must retain the above copyright
|
|
Packit |
8dc392 |
// notice, this list of conditions and the following disclaimer.
|
|
Packit |
8dc392 |
// * Redistributions in binary form must reproduce the above
|
|
Packit |
8dc392 |
// copyright notice, this list of conditions and the following disclaimer
|
|
Packit |
8dc392 |
// in the documentation and/or other materials provided with the
|
|
Packit |
8dc392 |
// distribution.
|
|
Packit |
8dc392 |
// * Neither the name of Industrial Light & Magic nor the names of
|
|
Packit |
8dc392 |
// its contributors may be used to endorse or promote products derived
|
|
Packit |
8dc392 |
// from this software without specific prior written permission.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
8dc392 |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
8dc392 |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
Packit |
8dc392 |
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
Packit |
8dc392 |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
8dc392 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
8dc392 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit |
8dc392 |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit |
8dc392 |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit |
8dc392 |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
8dc392 |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
///////////////////////////////////////////////////////////////////////////
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//------------------------------------------------------------------------
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Functions to control floating point exceptions.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
//------------------------------------------------------------------------
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#include "IexMathFpu.h"
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#include <stdint.h>
|
|
Packit |
8dc392 |
#include <IlmBaseConfig.h>
|
|
Packit |
8dc392 |
#include <stdio.h>
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#if 0
|
|
Packit |
8dc392 |
#include <iostream>
|
|
Packit |
8dc392 |
#define debug(x) (std::cout << x << std::flush)
|
|
Packit |
8dc392 |
#else
|
|
Packit |
8dc392 |
#define debug(x)
|
|
Packit |
8dc392 |
#endif
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#if defined(HAVE_UCONTEXT_H) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86))
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#include <ucontext.h>
|
|
Packit |
8dc392 |
#include <signal.h>
|
|
Packit |
8dc392 |
#include <iostream>
|
|
Packit |
8dc392 |
#include <stdint.h>
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
IEX_INTERNAL_NAMESPACE_SOURCE_ENTER
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
namespace FpuControl
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//-------------------------------------------------------------------
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Modern x86 processors and all AMD64 processors have two
|
|
Packit |
8dc392 |
// sets of floating-point control/status registers: cw and sw
|
|
Packit |
8dc392 |
// for legacy x87 stack-based arithmetic, and mxcsr for
|
|
Packit |
8dc392 |
// SIMD arithmetic. When setting exception masks or checking
|
|
Packit |
8dc392 |
// for exceptions, we must set/check all relevant registers,
|
|
Packit |
8dc392 |
// since applications may contain code that uses either FP
|
|
Packit |
8dc392 |
// model.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// These functions handle both FP models for x86 and AMD64.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
//-------------------------------------------------------------------
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//-------------------------------------------------------------------
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Restore the control register state from a signal handler
|
|
Packit |
8dc392 |
// user context, optionally clearing the exception bits
|
|
Packit |
8dc392 |
// in the restored control register, if applicable.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
//-------------------------------------------------------------------
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void restoreControlRegs (const ucontext_t & ucon,
|
|
Packit |
8dc392 |
bool clearExceptions = false);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//------------------------------------------------------------
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Set exception mask bits in the control register state.
|
|
Packit |
8dc392 |
// A value of 1 means the exception is masked, a value of
|
|
Packit |
8dc392 |
// 0 means the exception is enabled.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// setExceptionMask returns the previous mask value. If
|
|
Packit |
8dc392 |
// the 'exceptions' pointer is non-null, it returns in
|
|
Packit |
8dc392 |
// this argument the FPU exception bits.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
//------------------------------------------------------------
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
const int INVALID_EXC = (1<<0);
|
|
Packit |
8dc392 |
const int DENORMAL_EXC = (1<<1);
|
|
Packit |
8dc392 |
const int DIVZERO_EXC = (1<<2);
|
|
Packit |
8dc392 |
const int OVERFLOW_EXC = (1<<3);
|
|
Packit |
8dc392 |
const int UNDERFLOW_EXC = (1<<4);
|
|
Packit |
8dc392 |
const int INEXACT_EXC = (1<<5);
|
|
Packit |
8dc392 |
const int ALL_EXC = INVALID_EXC | DENORMAL_EXC | DIVZERO_EXC |
|
|
Packit |
8dc392 |
OVERFLOW_EXC | UNDERFLOW_EXC | INEXACT_EXC;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int setExceptionMask (int mask, int * exceptions = 0);
|
|
Packit |
8dc392 |
int getExceptionMask ();
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//---------------------------------------------
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Get/clear the exception bits in the FPU.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
//---------------------------------------------
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int getExceptions ();
|
|
Packit |
8dc392 |
void clearExceptions ();
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//------------------------------------------------------------------
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Everything below here is implementation. Do not use these
|
|
Packit |
8dc392 |
// constants or functions in your applications or libraries.
|
|
Packit |
8dc392 |
// This is not the code you're looking for. Move along.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Optimization notes -- on a Pentium 4, at least, it appears
|
|
Packit |
8dc392 |
// to be faster to get the mxcsr first and then the cw; and to
|
|
Packit |
8dc392 |
// set the cw first and then the mxcsr. Also, it seems to
|
|
Packit |
8dc392 |
// be faster to clear the sw exception bits after setting
|
|
Packit |
8dc392 |
// cw and mxcsr.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
//------------------------------------------------------------------
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
static inline uint16_t
|
|
Packit |
8dc392 |
getSw ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
uint16_t sw;
|
|
Packit |
8dc392 |
asm volatile ("fnstsw %0" : "=m" (sw) : );
|
|
Packit |
8dc392 |
return sw;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
static inline void
|
|
Packit |
8dc392 |
setCw (uint16_t cw)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
asm volatile ("fldcw %0" : : "m" (cw) );
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
static inline uint16_t
|
|
Packit |
8dc392 |
getCw ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
uint16_t cw;
|
|
Packit |
8dc392 |
asm volatile ("fnstcw %0" : "=m" (cw) : );
|
|
Packit |
8dc392 |
return cw;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
static inline void
|
|
Packit |
8dc392 |
setMxcsr (uint32_t mxcsr, bool clearExceptions)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
mxcsr &= clearExceptions ? 0xffffffc0 : 0xffffffff;
|
|
Packit |
8dc392 |
asm volatile ("ldmxcsr %0" : : "m" (mxcsr) );
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
static inline uint32_t
|
|
Packit |
8dc392 |
getMxcsr ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
uint32_t mxcsr;
|
|
Packit |
8dc392 |
asm volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
Packit |
8dc392 |
return mxcsr;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
static inline int
|
|
Packit |
8dc392 |
calcMask (uint16_t cw, uint32_t mxcsr)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Hopefully, if the user has been using FpuControl functions,
|
|
Packit |
8dc392 |
// the masks are the same, but just in case they're not, we
|
|
Packit |
8dc392 |
// AND them together to report the proper subset of the masks.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
return (cw & ALL_EXC) & ((mxcsr >> 7) & ALL_EXC);
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
inline int
|
|
Packit |
8dc392 |
setExceptionMask (int mask, int * exceptions)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
uint16_t cw = getCw ();
|
|
Packit |
8dc392 |
uint32_t mxcsr = getMxcsr ();
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (exceptions)
|
|
Packit |
8dc392 |
*exceptions = (mxcsr & ALL_EXC) | (getSw () & ALL_EXC);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int oldmask = calcMask (cw, mxcsr);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// The exception constants are chosen very carefully so that
|
|
Packit |
8dc392 |
// we can do a simple mask and shift operation to insert
|
|
Packit |
8dc392 |
// them into the control words. The mask operation is for
|
|
Packit |
8dc392 |
// safety, in case the user accidentally set some other
|
|
Packit |
8dc392 |
// bits in the exception mask.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
mask &= ALL_EXC;
|
|
Packit |
8dc392 |
cw = (cw & ~ALL_EXC) | mask;
|
|
Packit |
8dc392 |
mxcsr = (mxcsr & ~(ALL_EXC << 7)) | (mask << 7);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
setCw (cw);
|
|
Packit |
8dc392 |
setMxcsr (mxcsr, false);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
return oldmask;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
inline int
|
|
Packit |
8dc392 |
getExceptionMask ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
uint32_t mxcsr = getMxcsr ();
|
|
Packit |
8dc392 |
uint16_t cw = getCw ();
|
|
Packit |
8dc392 |
return calcMask (cw, mxcsr);
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
inline int
|
|
Packit |
8dc392 |
getExceptions ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
return (getMxcsr () | getSw ()) & ALL_EXC;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
clearExceptions ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
uint32_t mxcsr = getMxcsr () & 0xffffffc0;
|
|
Packit |
8dc392 |
asm volatile ("ldmxcsr %0\n"
|
|
Packit |
8dc392 |
"fnclex"
|
|
Packit |
8dc392 |
: : "m" (mxcsr) );
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
// If the fpe was taken while doing a float-to-int cast using the x87,
|
|
Packit |
8dc392 |
// the rounding mode and possibly the precision will be wrong. So instead
|
|
Packit |
8dc392 |
// of restoring to the state as of the fault, we force the rounding mode
|
|
Packit |
8dc392 |
// to be 'nearest' and the precision to be double extended.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// rounding mode is in bits 10-11, value 00 == round to nearest
|
|
Packit |
8dc392 |
// precision is in bits 8-9, value 11 == double extended (80-bit)
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
const uint16_t cwRestoreMask = ~((3 << 10) | (3 << 8));
|
|
Packit |
8dc392 |
const uint16_t cwRestoreVal = (0 << 10) | (3 << 8);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#ifdef ILMBASE_HAVE_CONTROL_REGISTER_SUPPORT
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
inline void
|
|
Packit |
8dc392 |
restoreControlRegs (const ucontext_t & ucon, bool clearExceptions)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
setCw ((ucon.uc_mcontext.fpregs->cwd & cwRestoreMask) | cwRestoreVal);
|
|
Packit |
8dc392 |
setMxcsr (ucon.uc_mcontext.fpregs->mxcsr, clearExceptions);
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#else
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Ugly, the mxcsr isn't defined in GNU libc ucontext_t, but
|
|
Packit |
8dc392 |
// it's passed to the signal handler by the kernel. Use
|
|
Packit |
8dc392 |
// the kernel's version of the ucontext to get it, see
|
|
Packit |
8dc392 |
// <asm/sigcontext.h>
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#include <asm/sigcontext.h>
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
inline void
|
|
Packit |
8dc392 |
restoreControlRegs (const ucontext_t & ucon, bool clearExceptions)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
setCw ((ucon.uc_mcontext.fpregs->cw & cwRestoreMask) | cwRestoreVal);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
_fpstate * kfp = reinterpret_cast<_fpstate *> (ucon.uc_mcontext.fpregs);
|
|
Packit |
8dc392 |
setMxcsr (kfp->magic == 0 ? kfp->mxcsr : 0, clearExceptions);
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#endif
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
} // namespace FpuControl
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
namespace {
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
volatile FpExceptionHandler fpeHandler = 0;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
extern "C" void
|
|
Packit |
8dc392 |
catchSigFpe (int sig, siginfo_t *info, ucontext_t *ucon)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
debug ("catchSigFpe (sig = "<< sig << ", ...)\n");
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
FpuControl::restoreControlRegs (*ucon, true);
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (fpeHandler == 0)
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (info->si_code == SI_USER)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler (0, "Floating-point exception, caused by "
|
|
Packit |
8dc392 |
"a signal sent from another process.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (sig == SIGFPE)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
switch (info->si_code)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// IEEE 754 floating point exceptions:
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_FLTDIV:
|
|
Packit |
8dc392 |
fpeHandler (IEEE_DIVZERO, "Floating-point division by zero.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_FLTOVF:
|
|
Packit |
8dc392 |
fpeHandler (IEEE_OVERFLOW, "Floating-point overflow.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_FLTUND:
|
|
Packit |
8dc392 |
fpeHandler (IEEE_UNDERFLOW, "Floating-point underflow.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_FLTRES:
|
|
Packit |
8dc392 |
fpeHandler (IEEE_INEXACT, "Inexact floating-point result.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_FLTINV:
|
|
Packit |
8dc392 |
fpeHandler (IEEE_INVALID, "Invalid floating-point operation.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// Other arithmetic exceptions which can also
|
|
Packit |
8dc392 |
// be trapped by the operating system:
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_INTDIV:
|
|
Packit |
8dc392 |
fpeHandler (0, "Integer division by zero.");
|
|
Packit |
8dc392 |
break;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_INTOVF:
|
|
Packit |
8dc392 |
fpeHandler (0, "Integer overflow.");
|
|
Packit |
8dc392 |
break;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
case FPE_FLTSUB:
|
|
Packit |
8dc392 |
fpeHandler (0, "Subscript out of range.");
|
|
Packit |
8dc392 |
break;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
fpeHandler (0, "Floating-point exception.");
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
} // namespace
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
setFpExceptions (int when)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
int mask = FpuControl::ALL_EXC;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (when & IEEE_OVERFLOW)
|
|
Packit |
8dc392 |
mask &= ~FpuControl::OVERFLOW_EXC;
|
|
Packit |
8dc392 |
if (when & IEEE_UNDERFLOW)
|
|
Packit |
8dc392 |
mask &= ~FpuControl::UNDERFLOW_EXC;
|
|
Packit |
8dc392 |
if (when & IEEE_DIVZERO)
|
|
Packit |
8dc392 |
mask &= ~FpuControl::DIVZERO_EXC;
|
|
Packit |
8dc392 |
if (when & IEEE_INEXACT)
|
|
Packit |
8dc392 |
mask &= ~FpuControl::INEXACT_EXC;
|
|
Packit |
8dc392 |
if (when & IEEE_INVALID)
|
|
Packit |
8dc392 |
mask &= ~FpuControl::INVALID_EXC;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// The Linux kernel apparently sometimes passes
|
|
Packit |
8dc392 |
// incorrect si_info to signal handlers unless
|
|
Packit |
8dc392 |
// the exception flags are cleared.
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
// XXX is this still true on 2.4+ kernels?
|
|
Packit |
8dc392 |
//
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
FpuControl::setExceptionMask (mask);
|
|
Packit |
8dc392 |
FpuControl::clearExceptions ();
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int
|
|
Packit |
8dc392 |
fpExceptions ()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
int mask = FpuControl::getExceptionMask ();
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int when = 0;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::OVERFLOW_EXC))
|
|
Packit |
8dc392 |
when |= IEEE_OVERFLOW;
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::UNDERFLOW_EXC))
|
|
Packit |
8dc392 |
when |= IEEE_UNDERFLOW;
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::DIVZERO_EXC))
|
|
Packit |
8dc392 |
when |= IEEE_DIVZERO;
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::INEXACT_EXC))
|
|
Packit |
8dc392 |
when |= IEEE_INEXACT;
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::INVALID_EXC))
|
|
Packit |
8dc392 |
when |= IEEE_INVALID;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
return when;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
handleExceptionsSetInRegisters()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
if (fpeHandler == 0)
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int mask = FpuControl::getExceptionMask ();
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int exc = FpuControl::getExceptions();
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::DIVZERO_EXC) && (exc & FpuControl::DIVZERO_EXC))
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler(IEEE_DIVZERO, "Floating-point division by zero.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::OVERFLOW_EXC) && (exc & FpuControl::OVERFLOW_EXC))
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler(IEEE_OVERFLOW, "Floating-point overflow.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::UNDERFLOW_EXC) && (exc & FpuControl::UNDERFLOW_EXC))
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler(IEEE_UNDERFLOW, "Floating-point underflow.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::INEXACT_EXC) && (exc & FpuControl::INEXACT_EXC))
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler(IEEE_INEXACT, "Inexact floating-point result.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
if (!(mask & FpuControl::INVALID_EXC) && (exc & FpuControl::INVALID_EXC))
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler(IEEE_INVALID, "Invalid floating-point operation.");
|
|
Packit |
8dc392 |
return;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
setFpExceptionHandler (FpExceptionHandler handler)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
if (fpeHandler == 0)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
struct sigaction action;
|
|
Packit |
8dc392 |
sigemptyset (&action.sa_mask);
|
|
Packit |
8dc392 |
action.sa_flags = SA_SIGINFO | SA_NOMASK;
|
|
Packit |
8dc392 |
action.sa_sigaction = (void (*) (int, siginfo_t *, void *)) catchSigFpe;
|
|
Packit |
8dc392 |
action.sa_restorer = 0;
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
sigaction (SIGFPE, &action, 0);
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
fpeHandler = handler;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
IEX_INTERNAL_NAMESPACE_SOURCE_EXIT
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#else
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#include <signal.h>
|
|
Packit |
8dc392 |
#include <assert.h>
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
IEX_INTERNAL_NAMESPACE_SOURCE_ENTER
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
namespace
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
volatile FpExceptionHandler fpeHandler = 0;
|
|
Packit |
8dc392 |
void fpExc_(int x)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
if (fpeHandler != 0)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
fpeHandler(x, "");
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
else
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
assert(0 != "Floating point exception");
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
setFpExceptions( int )
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
setFpExceptionHandler (FpExceptionHandler handler)
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
// improve floating point exception handling nanoscopically above "nothing at all"
|
|
Packit |
8dc392 |
fpeHandler = handler;
|
|
Packit |
8dc392 |
signal(SIGFPE, fpExc_);
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
int
|
|
Packit |
8dc392 |
fpExceptions()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
return 0;
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
void
|
|
Packit |
8dc392 |
handleExceptionsSetInRegisters()
|
|
Packit |
8dc392 |
{
|
|
Packit |
8dc392 |
// No implementation on this platform
|
|
Packit |
8dc392 |
}
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
IEX_INTERNAL_NAMESPACE_SOURCE_EXIT
|
|
Packit |
8dc392 |
|
|
Packit |
8dc392 |
#endif
|