windows-nt/Source/XPSP1/NT/base/wow64/mscpu/fraglib/fpustore.c
2020-09-26 16:20:57 +08:00

590 lines
14 KiB
C

/*++
Copyright (c) 1995-1998 Microsoft Corporation
Module Name:
fpustore.c
Abstract:
Floating point store 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;
//
// Forward declarations
//
__int64 CastDoubleToInt64(double d); // in alpha\fphelp.s
#if !NATIVE_NAN_IS_INTEL_FORMAT
//
// Forward declarations
//
NPXPUTINTELR4(PutIntelR4_VALID);
NPXPUTINTELR4(PutIntelR4_ZERO);
NPXPUTINTELR4(PutIntelR4_SPECIAL);
NPXPUTINTELR4(PutIntelR4_EMPTY);
NPXPUTINTELR8(PutIntelR8_VALID);
NPXPUTINTELR8(PutIntelR8_ZERO);
NPXPUTINTELR8(PutIntelR8_SPECIAL);
NPXPUTINTELR8(PutIntelR8_EMPTY);
//
// Jump tables
//
const NpxPutIntelR4 PutIntelR4Table[TAG_MAX] = {
PutIntelR4_VALID,
PutIntelR4_ZERO,
PutIntelR4_SPECIAL,
PutIntelR4_EMPTY
};
const NpxPutIntelR8 PutIntelR8Table[TAG_MAX] = {
PutIntelR8_VALID,
PutIntelR8_ZERO,
PutIntelR8_SPECIAL,
PutIntelR8_EMPTY
};
NPXPUTINTELR4(PutIntelR4_VALID)
{
FLOAT f = (FLOAT)Fp->r64;
PUT_LONG(pIntelReal, *(DWORD *)&f);
}
NPXPUTINTELR4(PutIntelR4_ZERO)
{
//
// This cannot simply write a constant 0.0 to memory as it must
// copy the correct sign from the 0.0 in the FP register.
//
PUT_LONG(pIntelReal, Fp->rdw[1]);
}
NPXPUTINTELR4(PutIntelR4_SPECIAL)
{
switch (Fp->TagSpecial) {
default:
CPUASSERT(FALSE); // unknown tag - fall into TAG_INDEF
case TAG_SPECIAL_INFINITY:
case TAG_SPECIAL_DENORM:
PutIntelR4_VALID(pIntelReal, Fp);
break;
case TAG_SPECIAL_INDEF:
// Write out the R4 indefinite bit pattern
PUT_LONG(pIntelReal, 0xffc00000);
break;
case TAG_SPECIAL_QNAN:
case TAG_SPECIAL_SNAN: {
DWORD d[2];
FLOAT f;
//
// Truncate the R8 to an R4, and toggle the top bit of the mantissa
// to form an Intel QNAN/SNAN (which is different than a native
// QNAN/SNAN).
//
d[0] = Fp->rdw[0];
d[1] = Fp->rdw[1] ^ 0x00400000;
f = *(FLOAT *)d;
PUT_LONG(pIntelReal, *(DWORD *)&f);
}
break;
}
}
NPXPUTINTELR4(PutIntelR4_EMPTY)
{
//
// It is assumed that callers of PutIntelR4() have already handled
// TAG_EMPTY by raising an exception or converting it to TAG_INDEF.
//
CPUASSERT(FALSE);
}
NPXPUTINTELR8(PutIntelR8_VALID)
{
*(UNALIGNED DOUBLE *)pIntelReal = Fp->r64;
}
NPXPUTINTELR8(PutIntelR8_ZERO)
{
//
// This cannot simply write a constant 0.0 to memory as it must
// copy the correct sign from the 0.0 in the FP register.
//
*(UNALIGNED DOUBLE *)pIntelReal = Fp->r64;
}
NPXPUTINTELR8(PutIntelR8_SPECIAL)
{
DWORD *pdw = (DWORD *)pIntelReal;
switch (Fp->TagSpecial) {
default:
CPUASSERT(FALSE); // unknown tag - fall into TAG_INDEF
case TAG_SPECIAL_DENORM:
case TAG_SPECIAL_INFINITY:
// Both can be done as a simple R8-toR8 copy
PutIntelR8_VALID(pIntelReal, Fp);
break;
case TAG_SPECIAL_INDEF:
// Write out an Intel Indefinite
PUT_LONG(pdw, 0);
PUT_LONG((pdw+1), 0xfff80000);
break;
case TAG_SPECIAL_QNAN:
case TAG_SPECIAL_SNAN:
//
// Toggle the top bit of the mantissa to form an Intel QNAN/SNAN
// (which is different than a native QNAN/SNAN).
//
PUT_LONG(pdw, Fp->rdw[0]);
PUT_LONG((pdw+1), Fp->rdw[1] ^ 0x00080000);
break;
}
}
NPXPUTINTELR8(PutIntelR8_EMPTY)
{
//
// It is assumed that callers of PutIntelR8() have already handled
// TAG_EMPTY by raising an exception or converting it to TAG_INDEF.
//
CPUASSERT(FALSE);
}
#endif //!NATIVE_NAN_IS_INTEL_FORMAT
FRAG1(FIST16, SHORT) // FIST m16int
{
PFPREG ST0 = cpu->FpST0;
__int64 i64;
int Exponent;
SHORT i16;
FpArithDataPreamble(cpu, pop1);
switch (ST0->Tag) {
case TAG_VALID:
Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
//
if (Exponent >= 64) {
//
// Exponent is too big - this cannot be converted to an __int64
// Raise I exception on overflow, or write 0x8000 for masked
// exception.
//
IntOverflow:
if (HandleInvalidOp(cpu)) {
return;
}
PUT_SHORT(pop1, 0x8000);
} else {
i64 = CastDoubleToInt64(ST0->r64);
i16 = (SHORT)i64;
if ((__int64)i16 != i64) {
goto IntOverflow;
}
PUT_SHORT(pop1, i16);
}
break;
case TAG_ZERO:
PUT_SHORT(pop1, 0);
break;
case TAG_SPECIAL:
if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
i64 = CastDoubleToInt64(ST0->r64);
PUT_SHORT(pop1, (SHORT)i64);
} else if (!HandleInvalidOp(cpu)) {
// INFINITY and NANs are all invalid operations, and the masked
// behavior is to write 0x8000
PUT_SHORT(pop1, 0x8000);
}
break;
case TAG_EMPTY:
if (!HandleStackEmpty(cpu, ST0)) {
PUT_SHORT(pop1, 0x8000);
}
break;
}
}
FRAG1(FISTP16, SHORT) // FISTP m16int
{
PFPREG ST0 = cpu->FpST0;
__int64 i64;
int Exponent;
SHORT i16;
FpArithDataPreamble(cpu, pop1);
switch (ST0->Tag) {
case TAG_VALID:
Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
if (Exponent >= 64) {
//
// Exponent is too big - this cannot be converted to an __int64
// Raise I exception on overflow, or write 0x8000 for masked
// exception.
//
IntOverflow:
if (HandleInvalidOp(cpu)) {
return;
}
PUT_SHORT(pop1, 0x8000);
} else {
i64 = CastDoubleToInt64(ST0->r64);
i16 = (SHORT)i64;
if ((__int64)i16 != i64) {
goto IntOverflow;
}
PUT_SHORT(pop1, i16);
}
POPFLT;
break;
case TAG_ZERO:
PUT_SHORT(pop1, 0);
break;
case TAG_SPECIAL:
if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
i64 = CastDoubleToInt64(ST0->r64);
PUT_SHORT(pop1, (SHORT)i64);
} else if (!HandleInvalidOp(cpu)) {
// INFINITY and NANs are all invalid operations, and the masked
// behavior is to write 0x8000
PUT_SHORT(pop1, 0x8000);
}
POPFLT;
break;
case TAG_EMPTY:
if (!HandleStackEmpty(cpu, ST0)) {
PUT_SHORT(pop1, 0x8000);
POPFLT;
}
break;
}
}
FRAG1(FIST32, LONG) // FIST m32int
{
PFPREG ST0 = cpu->FpST0;
__int64 i64;
int Exponent;
LONG i32;
FpArithDataPreamble(cpu, pop1);
switch (ST0->Tag) {
case TAG_VALID:
Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
if (Exponent >= 64) {
//
// Exponent is too big - this cannot be converted to an __int64
// Raise I exception on overflow, or write 0x80000000 for masked
// exception.
//
IntOverflow:
if (HandleInvalidOp(cpu)) {
return;
}
PUT_LONG(pop1, 0x80000000);
} else {
i64 = CastDoubleToInt64(ST0->r64);
i32 = (LONG)i64;
if ((__int64)i32 != i64) {
goto IntOverflow;
}
PUT_LONG(pop1, i32);
}
break;
case TAG_ZERO:
PUT_LONG(pop1, 0);
break;
case TAG_SPECIAL:
if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
i64 = CastDoubleToInt64(ST0->r64);
PUT_LONG(pop1, (LONG)i64);
} else if (!HandleInvalidOp(cpu)) {
// INFINITY and NANs are all invalid operations, and the masked
// behavior is to write 0x80000000
PUT_LONG(pop1, 0x80000000);
}
break;
case TAG_EMPTY:
if (!HandleStackEmpty(cpu, ST0)) {
PUT_LONG(pop1, 0x80000000);
POPFLT;
}
break;
}
}
FRAG1(FISTP32, LONG) // FISTP m32int
{
PFPREG ST0 = cpu->FpST0;
__int64 i64;
int Exponent;
LONG i32;
FpArithDataPreamble(cpu, pop1);
switch (ST0->Tag) {
case TAG_VALID:
Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
if (Exponent >= 64) {
//
// Exponent is too big - this cannot be converted to an __int64
// Raise I exception on overflow, or write 0x80000000 for masked
// exception.
//
IntOverflow:
if (HandleInvalidOp(cpu)) {
return;
}
PUT_LONG(pop1, 0x80000000);
} else {
i64 = CastDoubleToInt64(ST0->r64);
i32 = (LONG)i64;
if ((__int64)i32 != i64) {
goto IntOverflow;
}
PUT_LONG(pop1, i32);
}
POPFLT;
break;
case TAG_ZERO:
PUT_LONG(pop1, 0);
POPFLT;
break;
case TAG_SPECIAL:
if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
i64 = CastDoubleToInt64(ST0->r64);
PUT_LONG(pop1, (LONG)i64);
} else if (!HandleInvalidOp(cpu)) {
// INFINITY and NANs are all invalid operations, and the masked
// behavior is to write 0x80000000
PUT_LONG(pop1, 0x80000000);
}
POPFLT;
break;
case TAG_EMPTY:
if (!HandleStackEmpty(cpu, ST0)) {
PUT_LONG(pop1, 0x80000000);
POPFLT;
}
break;
}
}
FRAG1(FISTP64, LONGLONG) // FISTP m64int
{
PFPREG ST0 = cpu->FpST0;
__int64 i64;
int Exponent;
FpArithDataPreamble(cpu, pop1);
switch (ST0->Tag) {
case TAG_VALID:
Exponent = (int)((ST0->rdw[1] >> 20) & 0x7ff) - 1023;
if (Exponent >= 64) {
//
// Exponent is too big - this cannot be converted to an __int64,
// Raise I exception on overflow, or write 0x800...0 for masked
// exception
//
if (HandleInvalidOp(cpu)) {
return;
}
i64 = (__int64)0x8000000000000000i64;
} else {
i64 = CastDoubleToInt64(ST0->r64);
}
*(UNALIGNED LONGLONG *)pop1 = (LONGLONG)i64;
POPFLT;
break;
case TAG_ZERO:
*(UNALIGNED LONGLONG *)pop1 = 0;
POPFLT;
break;
case TAG_SPECIAL:
if (ST0->TagSpecial == TAG_SPECIAL_DENORM) {
i64 = CastDoubleToInt64(ST0->r64);
*(UNALIGNED LONGLONG *)pop1 = (LONGLONG)i64;
} else if (!HandleInvalidOp(cpu)) {
DWORD *pdw = (DWORD *)pop1;
// INFINITY and NANs are all invalid operations, and the masked
// behavior is to write 0x80000000
PUT_LONG(pdw, 0x00000000);
PUT_LONG((pdw+1), 0x80000000);
}
POPFLT;
break;
case TAG_EMPTY:
if (!HandleStackEmpty(cpu, ST0)) {
DWORD *pdw = (DWORD *)pop1;
PUT_LONG(pdw, 0x00000000);
PUT_LONG((pdw+1), 0x80000000);
POPFLT;
}
break;
}
}
FRAG1(FST32, FLOAT) // FST m32real
{
FpArithDataPreamble(cpu, pop1);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
PutIntelR4(pop1, cpu->FpST0);
}
FRAG1(FSTP32, FLOAT) // FSTP m32real
{
FpArithDataPreamble(cpu, pop1);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
PutIntelR4(pop1, cpu->FpST0);
POPFLT;
}
FRAG1(FST64, DOUBLE) // FST m64real
{
FpArithDataPreamble(cpu, pop1);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
PutIntelR8(pop1, cpu->FpST0);
}
FRAG1(FSTP64, DOUBLE) // FSTP m64real
{
FpArithDataPreamble(cpu, pop1);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
PutIntelR8(pop1, cpu->FpST0);
POPFLT;
}
FRAG1IMM(FST_STi, INT) // FST ST(i)
{
FpArithPreamble(cpu);
CPUASSERT( (op1 & 0x07) == op1);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
cpu->FpStack[ST(op1)] = *cpu->FpST0;
}
FRAG1IMM(FSTP_STi, INT) // FSTP ST(i)
{
FpArithPreamble(cpu);
CPUASSERT( (op1 & 0x07) == op1);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
//CONSIDER: According to TimP, FSTP ST(0) is commonly used to pop the
// stack. It may be worthwhile to test if op1==0 and skip the
// assignment and go right to the POPFLT.
cpu->FpStack[ST(op1)] = *cpu->FpST0;
POPFLT;
}
FRAG0(OPT_FSTP_ST0) // FSTP ST(0)
{
FpArithPreamble(cpu);
if (cpu->FpST0->Tag == TAG_EMPTY) {
if (HandleStackEmpty(cpu, cpu->FpST0)) {
// unmasked exception - abort the instruction
return;
}
}
POPFLT;
}