242 lines
6.2 KiB
C++
242 lines
6.2 KiB
C++
|
/**************************************************************************\
|
||
|
*
|
||
|
* Copyright (c) 1998 Microsoft Corporation
|
||
|
*
|
||
|
* Abstract:
|
||
|
*
|
||
|
* Floating point arithmetic support.
|
||
|
*
|
||
|
* History:
|
||
|
*
|
||
|
* 09/22/1999 agodfrey
|
||
|
* Created it.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#include "precomp.hpp"
|
||
|
|
||
|
#if DBG
|
||
|
|
||
|
// We need the definition of Globals::IsNt, but we don't want to include
|
||
|
// the whole of the ..\common\globals.hpp file.
|
||
|
|
||
|
namespace Globals
|
||
|
{
|
||
|
extern BOOL IsNt; // Are we running on any version of NT?
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
FPUStateSaver::AssertMode(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
if (SaveLevel <= 0)
|
||
|
{
|
||
|
ASSERTMSG(0, ("FPU mode not set via FPUStateSaver class"));
|
||
|
}
|
||
|
|
||
|
#if defined(_USE_X86_ASSEMBLY)
|
||
|
|
||
|
UINT32 tempState;
|
||
|
|
||
|
// Issue a FP barrier. Take all pending exceptions now.
|
||
|
|
||
|
_asm fwait
|
||
|
|
||
|
// get the control word
|
||
|
|
||
|
_asm fnstcw WORD PTR tempState
|
||
|
|
||
|
// ASSERT that the control word is still set to our prefered
|
||
|
// rounding mode and exception mask.
|
||
|
// If we take this ASSERT, there was an unauthorized change of
|
||
|
// the FPU rounding mode or exception mask settings between
|
||
|
// the FPUStateSaver constructor and destructor.
|
||
|
|
||
|
if(Globals::IsNt)
|
||
|
{
|
||
|
ASSERTMSG(
|
||
|
(tempState & FP_CTRL_MASK) == FP_CTRL_STATE,
|
||
|
("FPUStateSaver: Incorrect FPU Control Word")
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// On Win9x, many print drivers clear various exception masks
|
||
|
// and at least one video driver (ATI) changed the rounding control.
|
||
|
// While this could potentially cause rounding errors resulting in
|
||
|
// slightly different rasterization, and/or spurious exceptions, the
|
||
|
// change required to fix this (wrapping all calls to GDI) is too
|
||
|
// large to risk. Instead, we downgrade the ASSERT on win9x to a
|
||
|
// WARNING. We have not seen one of these exceptions or rounding
|
||
|
// errors causing an actual rasterization error yet and will fix
|
||
|
// those as they occur.
|
||
|
|
||
|
if((tempState & FP_CTRL_MASK) != FP_CTRL_STATE)
|
||
|
{
|
||
|
WARNING(("FPUStateSaver: Incorrect FPU Control Word"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
LONG FPUStateSaver::SaveLevel = 0;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/**************************************************************************\
|
||
|
*
|
||
|
* Function Description:
|
||
|
*
|
||
|
* Internal definition of MSVCRT's pow()
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* x - base
|
||
|
* y - exponent
|
||
|
*
|
||
|
* Return Value:
|
||
|
*
|
||
|
* x^y
|
||
|
*
|
||
|
* Notes:
|
||
|
*
|
||
|
* I purposefully didn't make our code use Office's implementation when
|
||
|
* we do the Office build. I want to avoid needing a separate build for
|
||
|
* Office if I can.
|
||
|
*
|
||
|
* Created:
|
||
|
*
|
||
|
* 10/19/1999 agodfrey
|
||
|
* Stole it from Office's code (mso\gel\gelfx86.cpp)
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
double
|
||
|
GpRuntime::Pow(
|
||
|
double x,
|
||
|
double y
|
||
|
)
|
||
|
{
|
||
|
|
||
|
#if defined(_USE_X86_ASSEMBLY)
|
||
|
|
||
|
static const double fphalf = 0.5;
|
||
|
static const double fpone = 1.0;
|
||
|
|
||
|
if ( x == 0.0 )
|
||
|
{
|
||
|
if ( y > 0.0 )
|
||
|
{
|
||
|
return 0.0;
|
||
|
}
|
||
|
|
||
|
if (y == 0.0)
|
||
|
{
|
||
|
WARNING(("call Pow(x, y) with x=0.0 and y=0.0"));
|
||
|
return 1.0; // sic
|
||
|
}
|
||
|
|
||
|
if ( y < 0.0 )
|
||
|
{
|
||
|
WARNING(("call Pow(x, y) with x=0.0 and y < 0.0"));
|
||
|
|
||
|
// return INF to comply with MSDN. Since we don't have INF defined
|
||
|
// in our header files, we use DBL_MAX which should be
|
||
|
// sufficient.
|
||
|
// !!!Todo[minliu], figure out how to return INF
|
||
|
|
||
|
return DBL_MAX;
|
||
|
}
|
||
|
}// x == 0.0
|
||
|
|
||
|
if (y == 0.0)
|
||
|
{
|
||
|
return 1.0;
|
||
|
}
|
||
|
|
||
|
__asm FLD QWORD PTR [y]; // becomes ST(1)
|
||
|
__asm FLD QWORD PTR [x]; // becomes ST
|
||
|
__asm FYL2X; // ST := ST(1) * log2(ST)
|
||
|
__asm FST QWORD PTR [x];
|
||
|
|
||
|
/* Do this in C++ just to avoid all the messing around with the condition
|
||
|
flags, keep x in ST(0) while doing this. */
|
||
|
if (fabs(x) < fpone)
|
||
|
{
|
||
|
/* The power is in the range which F2XM1 can handle. */
|
||
|
__asm F2XM1; // ST := 2^ST - 1
|
||
|
__asm FADD QWORD PTR [fpone]; // ST := 2^mantissa
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* The power needs to be handled as a separate fractional and whole
|
||
|
number part, as F2XM1 only handles fractions. Note that we don't
|
||
|
care about the rounding mode here - we just need to split x
|
||
|
into two parts one of which is <1.0. */
|
||
|
__asm FLD ST; // Duplicate ST
|
||
|
__asm FRNDINT; // Integral value in ST
|
||
|
//NB: doc bug in the x86 manual, the following does ST(1):=ST(1)-ST
|
||
|
__asm FSUB ST(1), ST; // Fractional value in ST(1)
|
||
|
__asm FXCH; // Factional value in ST
|
||
|
__asm F2XM1; // ST := 2^ST - 1
|
||
|
__asm FADD QWORD PTR [fpone]; // ST := 2^frac
|
||
|
__asm FSCALE; // ST := 2^frac * 2^integral
|
||
|
__asm FSTP ST(1); // FSCALE does not pop anything
|
||
|
}
|
||
|
|
||
|
__asm FSTP QWORD PTR [x];
|
||
|
return x;
|
||
|
|
||
|
#else
|
||
|
|
||
|
// No choice at the moment - we have to use the CRT. We'll watch what
|
||
|
// Office does when they start caring about IA64.
|
||
|
|
||
|
#undef pow
|
||
|
return pow(x,y);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/**************************************************************************\
|
||
|
*
|
||
|
* Function Description:
|
||
|
*
|
||
|
* Out-of-line version of exp()
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* x - input value
|
||
|
*
|
||
|
* Return Value:
|
||
|
*
|
||
|
* e^x
|
||
|
*
|
||
|
* Notes:
|
||
|
*
|
||
|
* Because we compile 'optimize for size', the compiler refuses to inline
|
||
|
* calls to exp() - because its implementation is quite long. So, we
|
||
|
* make an out-of-line version by setting the optimizations correctly
|
||
|
* here, and generating an inline version. Yes, I agree completely.
|
||
|
*
|
||
|
* Created:
|
||
|
*
|
||
|
* 10/20/1999 agodfrey
|
||
|
* Wrote it.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
#pragma optimize("gt", on)
|
||
|
|
||
|
double
|
||
|
GpRuntime::Exp(
|
||
|
double x
|
||
|
)
|
||
|
{
|
||
|
#undef exp
|
||
|
return exp(x);
|
||
|
}
|
||
|
#pragma optimize("", on)
|