|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
fpuload.c
Abstract:
Floating point load functions
Author:
04-Oct-1995 BarryBo
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include "wx86.h"
#include "cpuassrt.h"
#include "fragp.h"
#include "fpufragp.h"
#include "fpuarith.h"
ASSERTNAME;
VOID GetIntelR4( PFPREG Fp, FLOAT *pIntelReal ) /*++
Routine Description:
Load an Intel R4 and convert it to a native R4, accounting for the difference in how MIPS represents QNAN/SNAN.
NOTE: This is not in fpufrag.c due to a code-generator bug on PPC - irbexpr.c:932 asserts trying to inline this function. Moving it to a different file defeats the inliner.
Arguments:
Fp - floating-point register to load the R4 into pIntelReal - R4 value to load (in Intel format) Return Value:
None.
--*/ { DWORD d = GET_LONG(pIntelReal);
if ((d & 0x7f800000) == 0x7f800000) {
Fp->Tag = TAG_SPECIAL;
// Found some sort of NAN
if (d == 0xffc00000) { // Indefinite
// Create the native indefinite form
#if NATIVE_NAN_IS_INTEL_FORMAT
Fp->rdw[0] = 0; Fp->rdw[1] = 0xfff80000; #else
Fp->rdw[0] = 0xffffffff; Fp->rdw[1] = 0x7ff7ffff; #endif
Fp->TagSpecial = TAG_SPECIAL_INDEF;
} else if (d == 0x7f800000) { // +infinity
Fp->r64 = R8PositiveInfinity; Fp->TagSpecial = TAG_SPECIAL_INFINITY;
} else if (d == 0xff800000) { // -infinity
Fp->r64 = R8NegativeInfinity; Fp->TagSpecial = TAG_SPECIAL_INFINITY;
} else { // SNAN/QNAN
DWORD Sign;
if (d & 0x00400000) { //
// Intel QNAN
//
Fp->TagSpecial = TAG_SPECIAL_QNAN;
} else { //
// Intel SNAN
//
Fp->TagSpecial = TAG_SPECIAL_SNAN; }
#if !NATIVE_NAN_IS_INTEL_FORMAT
//
// Toggle the NAN to native format
//
d ^= 0x00400000; #endif
//
// Cast the r4 RISC QNAN to double. Don't trust the CRT to
// do the right thing - MIPS converts them both to INDEFINITE.
//
Sign = d & 0x80000000; d &= 0x007fffff; // grab the mantissa from the r4 (23 bits)
Fp->rdw[1] = Sign | 0x7ff00000 | (d >> 3); // store 20 bits of mantissa, plus sign
Fp->rdw[0] = d << 25; // store 3 bits of mantissa
}
} else { // denormal, zero, or number
// Coerce it to an R8
Fp->r64 = (DOUBLE)*(FLOAT *)&d;
// Compute its tag by looking at the value *after* the conversion,
// as the native FPU may have normalized the value
if (Fp->r64 == 0.0) { Fp->Tag = TAG_ZERO; } else if ((Fp->rdw[1] & 0x7ff00000) == 0) { // Exponent is 0 - R8 denormal
Fp->Tag = TAG_SPECIAL; Fp->TagSpecial = TAG_SPECIAL_DENORM; } else { Fp->Tag = TAG_VALID; #if DBG
SetTag(Fp); CPUASSERT(Fp->Tag == TAG_VALID); #endif
} } }
#if !NATIVE_NAN_IS_INTEL_FORMAT
VOID GetIntelR8( PFPREG Fp, DOUBLE *pIntelReal ) /*++
Routine Description:
Load an Intel R8 and convert it to a native R8, accounting for the difference in how MIPS represents QNAN/SNAN.
Arguments:
Fp - floating-point register to load the R8 into pIntelReal - R8 value to load (in Intel format) Return Value:
None.
--*/ { //
// Copy the R8 into the FP register
//
Fp->r64 = *(UNALIGNED DOUBLE *)pIntelReal;
//
// Compute its tag
//
SetTag(Fp);
//
// If the value is QNAN/SNAN/INDEF, convert it to native format
//
if (IS_TAG_NAN(Fp)) {
if (Fp->rdw[0] == 0 && Fp->rdw[1] == 0xfff80000) { // indefinite - make the R8 into a native indefinite
Fp->TagSpecial = TAG_SPECIAL_INDEF; Fp->rdw[0] = 0xffffffff; Fp->rdw[1] = 0x7ff7ffff; } else { if (Fp->rdw[1] & 0x00080000) { // top bit of mantissa is set - QNAN
Fp->TagSpecial = TAG_SPECIAL_QNAN; } else { // top bit of mantissa clear - SNAN
Fp->TagSpecial = TAG_SPECIAL_SNAN; } Fp->rdw[1] ^= 0x00080000; // invert the top bit of the mantissa
} } }
#endif //!NATIVE_NAN_IS_INTEL_FORMAT
VOID SetTag( PFPREG FpReg )
/*++
Routine Description:
Sets the Tag value corresponding to a r64 value in an FP register. Assumes the R8 value is in native format (ie. Intel NANs are already converted to native NANs).
Arguments:
FpReg - register to set Tag field in.
Return Value:
None
--*/
{ DWORD Exponent;
/* On average, the value will be zero or a valid real, so those cases
* have the fastest code paths. NANs tend to be less frequent and are * slower to calculate. */ Exponent = FpReg->rdw[1] & 0x7ff00000; if (Exponent == 0x7ff00000) { // exponent is all 1's - NAN of some sort
FpReg->Tag = TAG_SPECIAL;
if (FpReg->rdw[0] == 0 && (FpReg->rdw[1] & 0x7fffffff) == 0x7ff00000) { // Exponent is all 1s, mantissa is all 0s - Infinity
FpReg->TagSpecial = TAG_SPECIAL_INFINITY; } else {
#if NATIVE_NAN_IS_INTEL_FORMAT
if (FpReg->rdw[0] == 0 && FpReg->rdw[1] == 0xfff80000) { // indefinite
FpReg->TagSpecial = TAG_SPECIAL_INDEF; } else if (FpReg->rdw[1] & 0x00080000) { // top bit of mantissa is set - QNAN
FpReg->TagSpecial = TAG_SPECIAL_QNAN; } else { // Top bit of mantissa clear - but some mantissa bit set - QNAN
FpReg->TagSpecial = TAG_SPECIAL_SNAN; } #else //!NATIVE_NAN_IS_INTEL_FORMAT
if (FpReg->rdw[0] == 0xffffffff && FpReg->rdw[1] == 0x7ff7ffff) { // indefinite
FpReg->TagSpecial = TAG_SPECIAL_INDEF; } else if (FpReg->rdw[1] & 0x00080000) { // top bit of mantissa is set - SNAN
FpReg->TagSpecial = TAG_SPECIAL_SNAN; } else { // top bit of mantissa clear - QNAN
FpReg->TagSpecial = TAG_SPECIAL_QNAN; } #endif //!NATIVE_NAN_IS_INTEL_FORMAT
} } else if (Exponent == 0) { // exponent is 0 - DENORMAL or ZERO
if ((FpReg->rdw[1] & 0x1ffff) == 0 && FpReg->rdw[0] == 0) { // mantissa is all zeroes - ZERO
FpReg->Tag = TAG_ZERO; } else { FpReg->Tag = TAG_SPECIAL; FpReg->TagSpecial = TAG_SPECIAL_DENORM; } } else { // Exponent is not all 1's and not all 0's - a VALID
FpReg->Tag = TAG_VALID; } }
FRAG1(FILD16, SHORT) // FILD m16int
{ PFPREG ST0; FpArithDataPreamble(cpu, pop1);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { SHORT s;
s = (SHORT)GET_SHORT(pop1); ST0->r64 = (DOUBLE)s; if (s) { ST0->Tag = TAG_VALID; } else { ST0->Tag = TAG_ZERO; } } }
FRAG1(FILD32, LONG) // FILD m32int
{ PFPREG ST0; FpArithDataPreamble(cpu, pop1);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { LONG l;
l = (LONG)GET_LONG(pop1); ST0->r64 = (DOUBLE)l; if (l) { ST0->Tag = TAG_VALID; } else { ST0->Tag = TAG_ZERO; } } }
FRAG1(FILD64, LONGLONG) // FILD m64int
{ PFPREG ST0; FpArithDataPreamble(cpu, pop1);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { LONGLONG ll;
ll = *(UNALIGNED LONGLONG *)pop1; ST0->r64 = (DOUBLE)ll; if (ll) { ST0->Tag = TAG_VALID; } else { ST0->Tag = TAG_ZERO; } } }
FRAG1(FLD32, FLOAT) // FLD m32real
{ PFPREG ST0; FpArithDataPreamble(cpu, pop1);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { GetIntelR4(ST0, pop1); if (ST0->Tag == TAG_SPECIAL) { if (ST0->TagSpecial == TAG_SPECIAL_DENORM) { if (!(cpu->FpControlMask & FPCONTROL_DM)) { cpu->FpStatusES = 1; // Unmasked exception
//
// Instruction needs to be aborted due to unmasked
// exception. We've already hosed ST0, so "correct"
// it by popping the FP stack. Note that
// the contents of the register have been lost, which
// is a compatibility break with Intel.
//
POPFLT; } cpu->FpStatusExceptions |= FPCONTROL_DM; } else if (ST0->TagSpecial == TAG_SPECIAL_SNAN) { if (HandleSnan(cpu, ST0)) { //
// Instruction needs to be aborted due to unmasked
// exception. We've already hosed ST0, so "correct"
// it by popping the FP stack. Note that
// the contents of the register have been lost, which
// is a compatibility break with Intel.
//
POPFLT; } } } } }
FRAG1(FLD64, DOUBLE) // FLD m64real
{ PFPREG ST0; FpArithDataPreamble(cpu, pop1);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { GetIntelR8(ST0, pop1); if (ST0->Tag == TAG_SPECIAL) { if (ST0->TagSpecial == TAG_SPECIAL_DENORM) { if (!(cpu->FpControlMask & FPCONTROL_DM)) { cpu->FpStatusES = 1; // Unmasked exception
//
// Instruction needs to be aborted due to unmasked
// exception. We've already hosed ST0, so "correct"
// it by popping the FP stack. Note that
// the contents of the register have been lost, which
// is a compatibility break with Intel.
//
POPFLT; } cpu->FpStatusExceptions |= FPCONTROL_DM; } else if (ST0->TagSpecial == TAG_SPECIAL_SNAN) { if (HandleSnan(cpu, ST0)) { //
// Instruction needs to be aborted due to unmasked
// exception. We've already hosed ST0, so "correct"
// it by popping the FP stack. Note that
// the contents of the register have been lost, which
// is a compatibility break with Intel.
//
POPFLT; } } } } }
FRAG0(FLD1) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 1.0; ST0->Tag = TAG_VALID; } }
FRAG0(FLDL2T) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 2.3025850929940456840E0 / 6.9314718055994530942E-1; //log2(10) = ln10/ln2
ST0->Tag = TAG_VALID; } }
FRAG0(FLDL2E) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 1.4426950408889634074E0; ST0->Tag = TAG_VALID; } }
FRAG0(FLDPI) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 3.14159265358979323846; ST0->Tag = TAG_VALID; } }
FRAG0(FLDLG2) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 6.9314718055994530942E-1 / 2.3025850929940456840E0; ST0->Tag = TAG_VALID; } }
FRAG0(FLDLN2) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 6.9314718055994530942E-1; ST0->Tag = TAG_VALID; } }
FRAG1IMM(FLD_STi, INT) { PFPREG ST0; PFPREG STi;
FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
STi = &cpu->FpStack[ST(op1)]; PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = STi->r64; ST0->Tag = STi->Tag; ST0->TagSpecial = STi->TagSpecial; } }
FRAG0(FLDZ) { PFPREG ST0; FpArithPreamble(cpu);
cpu->FpStatusC1 = 0; // assume no error
PUSHFLT(ST0); if (ST0->Tag != TAG_EMPTY) { HandleStackFull(cpu, ST0); } else { ST0->r64 = 0.0; ST0->Tag = TAG_ZERO; } }
|