mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-24 20:00:41 +02:00
FEXCore: Rework X87 tag word handling
The FXSAVE and FSAVE tag words are written out in different formats, with FXSAVE using an abridged version that lacks the zero/special/valid distinction. Switch to using this abridged version internally for simplicity, and to allow the calculation of zero/special/valid distinction to be deferred until an fxsave instruction (in the future, currently the distinction is ignored and only valid/empty states are possible).
This commit is contained in:
1 parent
ea965810e5
commit
cb49373f47
7 files changed
+145
-115
No files matched your search
@@ -1811,14 +1811,12 @@ private:
|
||||
/** @} */
|
||||
|
||||
OrderedNode * GetX87Top();
|
||||
enum class X87Tag {
|
||||
Valid = 0b00,
|
||||
Zero = 0b01,
|
||||
Special = 0b10,
|
||||
Empty = 0b11
|
||||
};
|
||||
void SetX87TopTag(OrderedNode *Value, X87Tag Tag);
|
||||
OrderedNode *GetX87FTW(OrderedNode *Value);
|
||||
void SetX87ValidTag(OrderedNode *Value, bool Valid);
|
||||
OrderedNode *GetX87ValidTag(OrderedNode *Value);
|
||||
OrderedNode *GetX87Tag(OrderedNode *Value, OrderedNode *AbridgedFTW);
|
||||
OrderedNode *GetX87Tag(OrderedNode *Value);
|
||||
void SetX87FTW(OrderedNode *FTW);
|
||||
OrderedNode *GetX87FTW();
|
||||
void SetX87Top(OrderedNode *Value);
|
||||
|
||||
bool DestIsLockedMem(FEXCore::X86Tables::DecodedOp Op) const {
|
||||
|
||||
@@ -2622,10 +2622,10 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, OrderedNode *MemBase) {
|
||||
}
|
||||
|
||||
{
|
||||
// FTW
|
||||
// Abridged FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(4));
|
||||
auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
_StoreMem(GPRClass, 2, MemLocation, FTW, 2);
|
||||
auto AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
_StoreMem(GPRClass, 1, MemLocation, AbridgedFTW, 2);
|
||||
}
|
||||
|
||||
// BYTE | 0 1 | 2 3 | 4 | 5 | 6 7 | 8 9 | a b | c d | e f |
|
||||
@@ -2826,10 +2826,10 @@ void OpDispatchBuilder::RestoreX87State(OrderedNode *MemBase) {
|
||||
}
|
||||
|
||||
{
|
||||
// FTW
|
||||
// Abridged FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize, MemBase, _Constant(4));
|
||||
auto NewFTW = _LoadMem(GPRClass, 2, MemLocation, 2);
|
||||
_StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
auto NewAbridgedFTW = _LoadMem(GPRClass, 1, MemLocation, 2);
|
||||
_StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) {
|
||||
|
||||
@@ -12,6 +12,7 @@ $end_info$
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Utils/EnumUtils.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/FPState.h>
|
||||
#include <FEXCore/IR/IREmitter.h>
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -28,28 +29,59 @@ OrderedNode *OpDispatchBuilder::GetX87Top() {
|
||||
return _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, flags) + FEXCore::X86State::X87FLAG_TOP_LOC);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SetX87TopTag(OrderedNode *Value, X87Tag Tag) {
|
||||
void OpDispatchBuilder::SetX87ValidTag(OrderedNode *Value, bool Valid) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
OrderedNode *Mask = _Constant(0b11);
|
||||
// TODO: This can all be done with OpSize::i32Bit.
|
||||
auto TopOffset = _Lshl(IR::SizeToOpSize(std::max<uint8_t>(4, GetOpSize(Value))), Value, _Constant(1));
|
||||
Mask = _Lshl(OpSize::i64Bit, Mask, TopOffset);
|
||||
OrderedNode *NewFTW = _Andn(OpSize::i64Bit, FTW, Mask);
|
||||
if (Tag != X87Tag::Valid) {
|
||||
auto TagVal = _Lshl(OpSize::i64Bit, _Constant(ToUnderlying(Tag)), TopOffset);
|
||||
NewFTW = _Or(OpSize::i64Bit, NewFTW, TagVal);
|
||||
}
|
||||
|
||||
_StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
OrderedNode *RegMask = _Lshl(OpSize::i32Bit, _Constant(1), Value);
|
||||
OrderedNode *NewAbridgedFTW = Valid ? _Or(OpSize::i32Bit, AbridgedFTW, RegMask) : _Andn(OpSize::i32Bit, AbridgedFTW, RegMask);
|
||||
_StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::GetX87FTW(OrderedNode *Value) {
|
||||
auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
OrderedNode *Mask = _Constant(0b11);
|
||||
auto TopOffset = _Lshl(OpSize::i32Bit, Value, _Constant(1));
|
||||
auto NewFTW = _Lshr(OpSize::i32Bit, FTW, TopOffset);
|
||||
return _And(OpSize::i64Bit, NewFTW, Mask);
|
||||
OrderedNode *OpDispatchBuilder::GetX87ValidTag(OrderedNode *Value) {
|
||||
OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
return _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1));
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::GetX87Tag(OrderedNode *Value, OrderedNode *AbridgedFTW) {
|
||||
OrderedNode *RegValid = _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1));
|
||||
OrderedNode *X87Empty = _Constant(static_cast<uint8_t>(FPState::X87Tag::Empty));
|
||||
OrderedNode *X87Valid = _Constant(static_cast<uint8_t>(FPState::X87Tag::Valid));
|
||||
|
||||
return _Select(FEXCore::IR::COND_EQ,
|
||||
RegValid, _Constant(0),
|
||||
X87Empty, X87Valid);
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::GetX87Tag(OrderedNode *Value) {
|
||||
OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
return GetX87Tag(Value, AbridgedFTW);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SetX87FTW(OrderedNode *FTW) {
|
||||
OrderedNode *X87Empty = _Constant(static_cast<uint8_t>(FPState::X87Tag::Empty));
|
||||
OrderedNode *NewAbridgedFTW = _Constant(0);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
OrderedNode *RegTag = _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, FTW, _Constant(i * 2)), _Constant(0b11));
|
||||
OrderedNode *RegValid = _Select(FEXCore::IR::COND_EQ,
|
||||
RegTag, X87Empty,
|
||||
_Constant(0), _Constant(1));
|
||||
NewAbridgedFTW = _Or(OpSize::i32Bit, NewAbridgedFTW, _Lshl(OpSize::i32Bit, RegValid, _Constant(i)));
|
||||
}
|
||||
|
||||
_StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::GetX87FTW() {
|
||||
OrderedNode *AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
OrderedNode *FTW = _Constant(0);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
const auto RegTag = GetX87Tag(_Constant(i), AbridgedFTW);
|
||||
FTW = _Or(OpSize::i32Bit, FTW, _Lshl(OpSize::i32Bit, RegTag, _Constant(i * 2)));
|
||||
}
|
||||
|
||||
return FTW;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SetX87Top(OrderedNode *Value) {
|
||||
@@ -119,7 +151,7 @@ void OpDispatchBuilder::FLD(OpcodeArgs) {
|
||||
}
|
||||
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask);
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(converted, top, 16, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -138,7 +170,7 @@ void OpDispatchBuilder::FBLD(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto mask = _Constant(7);
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask);
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
// Read from memory
|
||||
@@ -156,7 +188,7 @@ void OpDispatchBuilder::FBSTP(OpcodeArgs) {
|
||||
StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1);
|
||||
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
}
|
||||
@@ -166,7 +198,7 @@ void OpDispatchBuilder::FLD_Const(OpcodeArgs) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto low = _Constant(Lower);
|
||||
@@ -196,7 +228,7 @@ void OpDispatchBuilder::FILD(OpcodeArgs) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
size_t read_width = GetSrcSize(Op);
|
||||
@@ -246,7 +278,7 @@ void OpDispatchBuilder::FST(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
// Set the new top now
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
@@ -272,7 +304,7 @@ void OpDispatchBuilder::FIST(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
// Set the new top now
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
@@ -321,7 +353,7 @@ void OpDispatchBuilder::FADD(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -384,7 +416,7 @@ void OpDispatchBuilder::FMUL(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -453,7 +485,7 @@ void OpDispatchBuilder::FDIV(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -537,7 +569,7 @@ void OpDispatchBuilder::FSUB(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
@@ -645,7 +677,7 @@ void OpDispatchBuilder::FRNDINT(OpcodeArgs) {
|
||||
void OpDispatchBuilder::FXTRACT(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -673,8 +705,8 @@ void OpDispatchBuilder::FNINIT(OpcodeArgs) {
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(Zero);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(Zero);
|
||||
|
||||
// Tags all get set to 0b11
|
||||
_StoreContext(2, GPRClass, _Constant(0xFFFF), offsetof(FEXCore::Core::CPUState, FTW));
|
||||
// Tags all get marked as invalid
|
||||
_StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
}
|
||||
|
||||
template<size_t width, bool Integer, OpDispatchBuilder::FCOMIFlags whichflags, bool poptwice>
|
||||
@@ -735,16 +767,16 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs) {
|
||||
|
||||
if constexpr (poptwice) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
}
|
||||
else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -806,7 +838,7 @@ void OpDispatchBuilder::FST(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
}
|
||||
@@ -892,7 +924,7 @@ void OpDispatchBuilder::X87ModifySTP<true>(OpcodeArgs);
|
||||
void OpDispatchBuilder::X87SinCos(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -913,7 +945,7 @@ void OpDispatchBuilder::X87FYL2X(OpcodeArgs) {
|
||||
|
||||
auto orig_top = GetX87Top();
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
|
||||
@@ -937,7 +969,7 @@ void OpDispatchBuilder::X87FYL2X(OpcodeArgs) {
|
||||
void OpDispatchBuilder::X87TAN(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 16, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -960,7 +992,7 @@ void OpDispatchBuilder::X87TAN(OpcodeArgs) {
|
||||
void OpDispatchBuilder::X87ATAN(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
|
||||
@@ -989,8 +1021,7 @@ void OpDispatchBuilder::X87LDENV(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size);
|
||||
_StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1033,8 +1064,7 @@ void OpDispatchBuilder::X87FNSTENV(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
_StoreMem(GPRClass, Size, MemLocation, FTW, Size);
|
||||
_StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1123,8 +1153,7 @@ void OpDispatchBuilder::X87FNSAVE(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
_StoreMem(GPRClass, Size, MemLocation, FTW, Size);
|
||||
_StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1192,8 +1221,7 @@ void OpDispatchBuilder::X87FRSTOR(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size);
|
||||
_StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size));
|
||||
}
|
||||
|
||||
OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7));
|
||||
@@ -1241,20 +1269,16 @@ void OpDispatchBuilder::X87FXAM(OpcodeArgs) {
|
||||
|
||||
// Claim this is a normal number
|
||||
// We don't support anything else
|
||||
auto FTW = GetX87FTW(top);
|
||||
auto X87Zero = _Constant(0b11);
|
||||
auto TopValid = GetX87ValidTag(top);
|
||||
auto ZeroConst = _Constant(0);
|
||||
auto OneConst = _Constant(1);
|
||||
|
||||
// In the case of Zero 0b11 then C3:C2:C0 is 0b101
|
||||
// In the case of top being invalid then C3:C2:C0 is 0b101
|
||||
auto C3 = _Select(FEXCore::IR::COND_EQ,
|
||||
FTW, X87Zero,
|
||||
OneConst, ZeroConst);
|
||||
|
||||
auto C2 = _Select(FEXCore::IR::COND_EQ,
|
||||
FTW, X87Zero,
|
||||
TopValid, OneConst,
|
||||
ZeroConst, OneConst);
|
||||
|
||||
auto C2 = TopValid;
|
||||
auto C0 = C3; // Mirror C3 until something other than zero is supported
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C0_LOC>(C0);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(C2);
|
||||
@@ -1350,7 +1374,7 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) {
|
||||
|
||||
void OpDispatchBuilder::X87EMMS(OpcodeArgs) {
|
||||
// Tags all get set to 0b11
|
||||
_StoreContext(2, GPRClass, _Constant(0xFFFF), offsetof(FEXCore::Core::CPUState, FTW));
|
||||
_StoreContext(1, GPRClass, _Constant(0), offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87FFREE(OpcodeArgs) {
|
||||
@@ -1362,7 +1386,7 @@ void OpDispatchBuilder::X87FFREE(OpcodeArgs) {
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, offset), _Constant(7));
|
||||
|
||||
// Set this argument's tag as empty now
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,8 +24,11 @@ class OrderedNode;
|
||||
|
||||
//Functions in X87.cpp (no change required)
|
||||
//GetX87Top
|
||||
//SetX87TopTag
|
||||
//GetX87FTW
|
||||
//SetX87ValidTag
|
||||
//GetX87ValidTag
|
||||
//GetX87Tag (will need changing once special tag handling is implemented)
|
||||
//SetX87FTW
|
||||
//GetX87FTW (will need changing once special tag handling is implemented)
|
||||
//SetX87Top
|
||||
//X87ModifySTP
|
||||
//EMMS
|
||||
@@ -57,8 +60,8 @@ void OpDispatchBuilder::FNINITF64(OpcodeArgs) {
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(Zero);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(Zero);
|
||||
|
||||
// Tags all get set to 0b11
|
||||
_StoreContext(2, GPRClass, _Constant(0xFFFF), offsetof(FEXCore::Core::CPUState, FTW));
|
||||
// Tags all get marked as invalid
|
||||
_StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {
|
||||
@@ -86,8 +89,7 @@ void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size);
|
||||
_StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +142,7 @@ void OpDispatchBuilder::FLDF64(OpcodeArgs) {
|
||||
}
|
||||
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask);
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(converted, top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -158,7 +160,7 @@ void OpDispatchBuilder::FBLDF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto mask = _Constant(7);
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), mask);
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
// Read from memory
|
||||
@@ -178,7 +180,7 @@ void OpDispatchBuilder::FBSTPF64(OpcodeArgs) {
|
||||
StoreResult_WithOpSize(FPRClass, Op, Op->Dest, converted, 10, 1);
|
||||
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
}
|
||||
@@ -188,7 +190,7 @@ void OpDispatchBuilder::FLDF64_Const(OpcodeArgs) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
auto data = _VCastFromGPR(8, 8, _Constant(num));
|
||||
// Write to ST[TOP]
|
||||
@@ -214,7 +216,7 @@ void OpDispatchBuilder::FILDF64(OpcodeArgs) {
|
||||
// Update TOP
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
size_t read_width = GetSrcSize(Op);
|
||||
@@ -247,7 +249,7 @@ void OpDispatchBuilder::FSTF64(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
// Set the new top now
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
@@ -276,7 +278,7 @@ void OpDispatchBuilder::FISTF64(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
// Set the new top now
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
@@ -326,7 +328,7 @@ void OpDispatchBuilder::FADDF64(OpcodeArgs) {
|
||||
auto result = _VFAdd(8, 8, a, b);
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -390,7 +392,7 @@ void OpDispatchBuilder::FMULF64(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -460,7 +462,7 @@ void OpDispatchBuilder::FDIVF64(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -546,7 +548,7 @@ void OpDispatchBuilder::FSUBF64(OpcodeArgs) {
|
||||
|
||||
if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
@@ -645,7 +647,7 @@ void OpDispatchBuilder::FRNDINTF64(OpcodeArgs) {
|
||||
void OpDispatchBuilder::FXTRACTF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -724,16 +726,16 @@ void OpDispatchBuilder::FCOMIF64(OpcodeArgs) {
|
||||
|
||||
if constexpr (poptwice) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
}
|
||||
else if ((Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) != 0) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(top, X87Tag::Empty);
|
||||
SetX87ValidTag(top, false);
|
||||
// Set the new top now
|
||||
top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, top, _Constant(1)), mask);
|
||||
SetX87Top(top);
|
||||
@@ -832,7 +834,7 @@ void OpDispatchBuilder::X87BinaryOpF64<IR::OP_F64SCALE>(OpcodeArgs);
|
||||
void OpDispatchBuilder::X87SinCosF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -853,7 +855,7 @@ void OpDispatchBuilder::X87FYL2XF64(OpcodeArgs) {
|
||||
|
||||
auto orig_top = GetX87Top();
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
|
||||
@@ -874,7 +876,7 @@ void OpDispatchBuilder::X87FYL2XF64(OpcodeArgs) {
|
||||
void OpDispatchBuilder::X87TANF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
auto top = _And(OpSize::i64Bit, _Sub(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87TopTag(top, X87Tag::Valid);
|
||||
SetX87ValidTag(top, true);
|
||||
SetX87Top(top);
|
||||
|
||||
auto a = _LoadContextIndexed(orig_top, 8, MMBaseOffset(), 16, FPRClass);
|
||||
@@ -894,7 +896,7 @@ void OpDispatchBuilder::X87TANF64(OpcodeArgs) {
|
||||
void OpDispatchBuilder::X87ATANF64(OpcodeArgs) {
|
||||
auto orig_top = GetX87Top();
|
||||
// if we are popping then we must first mark this location as empty
|
||||
SetX87TopTag(orig_top, X87Tag::Empty);
|
||||
SetX87ValidTag(orig_top, false);
|
||||
auto top = _And(OpSize::i64Bit, _Add(OpSize::i64Bit, orig_top, _Constant(1)), _Constant(7));
|
||||
SetX87Top(top);
|
||||
|
||||
@@ -949,8 +951,7 @@ void OpDispatchBuilder::X87FNSAVEF64(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto FTW = _LoadContext(2, GPRClass, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
_StoreMem(GPRClass, Size, MemLocation, FTW, Size);
|
||||
_StoreMem(GPRClass, Size, MemLocation, GetX87FTW(), Size);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1032,8 +1033,7 @@ void OpDispatchBuilder::X87FRSTORF64(OpcodeArgs) {
|
||||
{
|
||||
// FTW
|
||||
OrderedNode *MemLocation = _Add(OpSize::i64Bit, Mem, _Constant(Size * 2));
|
||||
auto NewFTW = _LoadMem(GPRClass, Size, MemLocation, Size);
|
||||
_StoreContext(2, GPRClass, NewFTW, offsetof(FEXCore::Core::CPUState, FTW));
|
||||
SetX87FTW(_LoadMem(GPRClass, Size, MemLocation, Size));
|
||||
}
|
||||
|
||||
OrderedNode *ST0Location = _Add(OpSize::i64Bit, Mem, _Constant(Size * 7));
|
||||
@@ -1085,20 +1085,16 @@ void OpDispatchBuilder::X87FXAMF64(OpcodeArgs) {
|
||||
|
||||
// Claim this is a normal number
|
||||
// We don't support anything else
|
||||
auto FTW = GetX87FTW(top);
|
||||
auto X87Zero = _Constant(0b11);
|
||||
auto TopValid = GetX87ValidTag(top);
|
||||
auto ZeroConst = _Constant(0);
|
||||
auto OneConst = _Constant(1);
|
||||
|
||||
// In the case of Zero 0b11 then C3:C2:C0 is 0b101
|
||||
// In the case of top being invalid then C3:C2:C0 is 0b101
|
||||
auto C3 = _Select(FEXCore::IR::COND_EQ,
|
||||
FTW, X87Zero,
|
||||
OneConst, ZeroConst);
|
||||
|
||||
auto C2 = _Select(FEXCore::IR::COND_EQ,
|
||||
FTW, X87Zero,
|
||||
TopValid, OneConst,
|
||||
ZeroConst, OneConst);
|
||||
|
||||
auto C2 = TopValid;
|
||||
auto C0 = C3; // Mirror C3 until something other than zero is supported
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C0_LOC>(C0);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(C2);
|
||||
|
||||
@@ -306,11 +306,11 @@ namespace {
|
||||
FEXCore::IR::InvalidClass,
|
||||
});
|
||||
|
||||
// FTW
|
||||
// AbridgedFTW
|
||||
ContextClassification->emplace_back(ContextMemberInfo {
|
||||
ContextMemberClassification {
|
||||
offsetof(FEXCore::Core::CPUState, FTW),
|
||||
sizeof(FEXCore::Core::CPUState::FTW),
|
||||
offsetof(FEXCore::Core::CPUState, AbridgedFTW),
|
||||
sizeof(FEXCore::Core::CPUState::AbridgedFTW),
|
||||
},
|
||||
ACCESS_NONE,
|
||||
FEXCore::IR::InvalidClass,
|
||||
|
||||
@@ -108,9 +108,9 @@ namespace FEXCore::Core {
|
||||
uint32_t base;
|
||||
} gdt[32]{};
|
||||
uint16_t FCW { 0x37F };
|
||||
uint16_t FTW { 0xFFFF };
|
||||
uint8_t AbridgedFTW{};
|
||||
|
||||
uint32_t _pad2[1];
|
||||
uint8_t _pad2[5];
|
||||
// Reference counter for FEX's per-thread deferred signals.
|
||||
// Counts the nesting depth of program sections that cause signals to be deferred.
|
||||
NonAtomicRefCounter<uint64_t> DeferredSignalRefCount;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace FEXCore::FPState {
|
||||
enum class X87Tag : uint8_t {
|
||||
Valid = 0b00,
|
||||
Zero = 0b01,
|
||||
Special = 0b10,
|
||||
Empty = 0b11
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user