mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-26 17:03:07 +01:00
OpcodeDispatcher: add cache
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
1 parent
7d939a3b3d
commit
46676ca376
7 files changed
+211
-52
No files matched your search
@@ -614,6 +614,20 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
|
||||
DecodedInfo = &Block.DecodedInstructions[i];
|
||||
bool IsLocked = DecodedInfo->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK;
|
||||
|
||||
// Do a partial register cache flush before every instruction. This
|
||||
// prevents cross-instruction static register caching, while allowing
|
||||
// context load/stores to be optimized within a block. Theoretically,
|
||||
// this flush is not required for correctness, all mandatory flushes are
|
||||
// included in instruction-specific handlers. Instead, this is a blunt
|
||||
// heuristic to make the register cache less aggressive, as the current
|
||||
// RA generates bad code in common cases with tied registers otherwise.
|
||||
//
|
||||
// However, it makes our exception handling behaviour more predictable.
|
||||
// It is potentially correctness bearing in that sense, but that is a
|
||||
// side effect here and (if that behaviour is required) we should handle
|
||||
// that more explicitly later.
|
||||
Thread->OpDispatcher->FlushRegisterCache(true);
|
||||
|
||||
if (ExtendedDebugInfo || Thread->OpDispatcher->CanHaveSideEffects(TableInfo, DecodedInfo)) {
|
||||
Thread->OpDispatcher->_GuestOpcode(Block.Entry + BlockInstructionsLength - GuestRIP);
|
||||
}
|
||||
|
||||
@@ -3366,8 +3366,8 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
auto Src2 = _LoadMem(GPRClass, Size, Dest_RSI, Size);
|
||||
|
||||
// We'll calculate PF/AF after the loop, so use them as temporaries here.
|
||||
_StoreRegister(Src1, Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
_StoreRegister(Src2, Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
StoreRegister(Core::CPUState::PF_AS_GREG, false, Src1);
|
||||
StoreRegister(Core::CPUState::AF_AS_GREG, false, Src2);
|
||||
|
||||
Ref TailCounter = LoadGPRRegister(X86State::REG_RCX);
|
||||
|
||||
@@ -3406,8 +3406,8 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
// Make sure to start a new block after ending this one
|
||||
{
|
||||
// Grab the sources from the last iteration so we can set flags.
|
||||
auto Src1 = _LoadRegister(Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
auto Src2 = _LoadRegister(Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
auto Src1 = LoadGPR(Core::CPUState::PF_AS_GREG);
|
||||
auto Src2 = LoadGPR(Core::CPUState::AF_AS_GREG);
|
||||
GenerateFlags_SUB(Op, Src2, Src1);
|
||||
}
|
||||
auto Jump_ = Jump();
|
||||
@@ -4362,7 +4362,7 @@ Ref OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86T
|
||||
const auto highIndex = Operand.Data.GPR.HighBits ? 1 : 0;
|
||||
|
||||
if (gpr >= FEXCore::X86State::REG_MM_0) {
|
||||
A.Base = _LoadContext(OpSize, FPRClass, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0]));
|
||||
A.Base = LoadContext(MM0Index + gpr - FEXCore::X86State::REG_MM_0);
|
||||
} else if (gpr >= FEXCore::X86State::REG_XMM_0) {
|
||||
const auto gprIndex = gpr - X86State::REG_XMM_0;
|
||||
|
||||
@@ -4399,7 +4399,7 @@ Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8_t Offset
|
||||
if (Size == -1) {
|
||||
Size = GPRSize;
|
||||
}
|
||||
Ref Reg = _LoadRegister(GPR, GPRClass, GPRSize);
|
||||
Ref Reg = LoadGPR(GPR);
|
||||
|
||||
if ((!AllowUpperGarbage && (Size != GPRSize)) || Offset != 0) {
|
||||
// Extract the subregister if requested.
|
||||
@@ -4413,11 +4413,6 @@ Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, int8_t Size, uint8_t Offset
|
||||
return Reg;
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::LoadXMMRegister(uint32_t XMM) {
|
||||
const auto VectorSize = CTX->HostFeatures.SupportsSVE256 ? 32 : 16;
|
||||
return _LoadRegister(XMM, FPRClass, VectorSize);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, const Ref Src, int8_t Size, uint8_t Offset) {
|
||||
const uint8_t GPRSize = CTX->GetGPRSize();
|
||||
if (Size == -1) {
|
||||
@@ -4427,16 +4422,14 @@ void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, const Ref Src, int8_t Siz
|
||||
Ref Reg = Src;
|
||||
if (Size != GPRSize || Offset != 0) {
|
||||
// Need to do an insert if not automatic size or zero offset.
|
||||
Reg = LoadGPRRegister(GPR);
|
||||
Reg = _Bfi(IR::SizeToOpSize(GPRSize), Size * 8, Offset, Reg, Src);
|
||||
Reg = _Bfi(IR::SizeToOpSize(GPRSize), Size * 8, Offset, LoadGPRRegister(GPR), Src);
|
||||
}
|
||||
|
||||
_StoreRegister(Reg, GPR, GPRClass, GPRSize);
|
||||
StoreRegister(GPR, false, Reg);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::StoreXMMRegister(uint32_t XMM, const Ref Src) {
|
||||
const auto VectorSize = CTX->HostFeatures.SupportsSVE256 ? 32 : 16;
|
||||
_StoreRegister(Src, XMM, FPRClass, VectorSize);
|
||||
StoreRegister(XMM, true, Src);
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::LoadSource(RegisterClassType Class, const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand,
|
||||
@@ -4455,7 +4448,8 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
|
||||
const auto gpr = Operand.Data.GPR.GPR;
|
||||
if (gpr >= FEXCore::X86State::REG_MM_0) {
|
||||
_StoreContext(OpSize, Class, Src, offsetof(FEXCore::Core::CPUState, mm[gpr - FEXCore::X86State::REG_MM_0]));
|
||||
LOGMAN_THROW_A_FMT(OpSize == 8, "full");
|
||||
StoreContext(MM0Index + gpr - FEXCore::X86State::REG_MM_0, Src);
|
||||
} else if (gpr >= FEXCore::X86State::REG_XMM_0) {
|
||||
const auto gprIndex = gpr - X86State::REG_XMM_0;
|
||||
const auto VectorSize = CTX->HostFeatures.SupportsSVE256 ? 32 : 16;
|
||||
@@ -4543,6 +4537,8 @@ void OpDispatchBuilder::ResetWorkingList() {
|
||||
DecodeFailure = false;
|
||||
ShouldDump = false;
|
||||
CurrentCodeBlock = nullptr;
|
||||
RegCache.Written = 0;
|
||||
RegCache.Cached = 0;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::UnhandledOp(OpcodeArgs) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <FEXCore/fextl/map.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <fmt/format.h>
|
||||
#include <stddef.h>
|
||||
@@ -1264,6 +1265,50 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void FlushRegisterCache(bool SRAOnly = false) {
|
||||
CalculateDeferredFlags();
|
||||
|
||||
const uint8_t GPRSize = CTX->GetGPRSize();
|
||||
const auto VectorSize = CTX->HostFeatures.SupportsSVE256 ? 32 : 16;
|
||||
|
||||
// Write backwards. This is a heuristic to improve coalescing, since we
|
||||
// often copy from (low) fixed GPRs to (high) PF/AF for celebrity
|
||||
// instructions like "add rax, 1". This hack will go away with clauses.
|
||||
uint64_t Bits = RegCache.Written;
|
||||
|
||||
// We have an SRA only mode that exists as a hack to make register caching
|
||||
// less aggressive. We should get rid of this once RA can take it.
|
||||
uint64_t Mask = ~0ULL;
|
||||
|
||||
if (SRAOnly) {
|
||||
const uint64_t GPRMask = ((1ull << (AFIndex - GPR0Index + 1)) - 1) << GPR0Index;
|
||||
const uint64_t FPRMask = ((1ull << (FPR15Index - FPR0Index + 1)) - 1) << FPR0Index;
|
||||
|
||||
Mask &= (GPRMask | FPRMask);
|
||||
Bits &= Mask;
|
||||
}
|
||||
|
||||
while (Bits != 0) {
|
||||
uint32_t Index = 63 - std::countl_zero(Bits);
|
||||
Ref Value = RegCache.Value[Index];
|
||||
|
||||
if (Index >= GPR0Index && Index <= AFIndex) {
|
||||
_StoreRegister(Value, Index - GPR0Index, GPRClass, GPRSize);
|
||||
} else if (Index >= FPR0Index && Index <= FPR15Index) {
|
||||
_StoreRegister(Value, Index - FPR0Index, FPRClass, VectorSize);
|
||||
} else if (Index == DFIndex) {
|
||||
_StoreFlag(Value, X86State::RFLAG_DF_RAW_LOC);
|
||||
} else {
|
||||
_StoreContext(CacheIndexToSize(Index), CacheIndexClass(Index), Value, CacheIndexToContextOffset(Index));
|
||||
}
|
||||
|
||||
Bits &= ~(1ull << Index);
|
||||
}
|
||||
|
||||
RegCache.Written &= ~Mask;
|
||||
RegCache.Cached &= ~Mask;
|
||||
}
|
||||
|
||||
protected:
|
||||
void SaveNZCV(IROps Op = OP_DUMMY) override {
|
||||
/* Some opcodes are conservatively marked as clobbering flags, but in fact
|
||||
@@ -1481,7 +1526,6 @@ private:
|
||||
void UpdatePrefixFromSegment(Ref Segment, uint32_t SegmentReg);
|
||||
|
||||
Ref LoadGPRRegister(uint32_t GPR, int8_t Size = -1, uint8_t Offset = 0, bool AllowUpperGarbage = false);
|
||||
Ref LoadXMMRegister(uint32_t XMM);
|
||||
void StoreGPRRegister(uint32_t GPR, const Ref Src, int8_t Size = -1, uint8_t Offset = 0);
|
||||
void StoreXMMRegister(uint32_t XMM, const Ref Src);
|
||||
|
||||
@@ -1697,9 +1741,9 @@ private:
|
||||
if (IsNZCV(BitOffset)) {
|
||||
InsertNZCV(BitOffset, Value, ValueOffset, MustMask);
|
||||
} else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) {
|
||||
_StoreRegister(Value, Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
StoreRegister(Core::CPUState::PF_AS_GREG, false, Value);
|
||||
} else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) {
|
||||
_StoreRegister(Value, Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
StoreRegister(Core::CPUState::AF_AS_GREG, false, Value);
|
||||
} else {
|
||||
if (ValueOffset || MustMask) {
|
||||
Value = _Bfe(OpSize::i32Bit, 1, ValueOffset, Value);
|
||||
@@ -1707,10 +1751,10 @@ private:
|
||||
|
||||
// For DF, we need to transform 0/1 into 1/-1
|
||||
if (BitOffset == FEXCore::X86State::RFLAG_DF_RAW_LOC) {
|
||||
Value = _SubShift(OpSize::i64Bit, _Constant(1), Value, ShiftType::LSL, 1);
|
||||
StoreDF(_SubShift(OpSize::i64Bit, _Constant(1), Value, ShiftType::LSL, 1));
|
||||
} else {
|
||||
_StoreFlag(Value, BitOffset);
|
||||
}
|
||||
|
||||
_StoreFlag(Value, BitOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1726,10 +1770,13 @@ private:
|
||||
|
||||
void InvalidateAF() {
|
||||
_InvalidateFlags((1u << X86State::RFLAG_AF_RAW_LOC));
|
||||
InvalidateReg(Core::CPUState::AF_AS_GREG);
|
||||
}
|
||||
|
||||
void InvalidatePF_AF() {
|
||||
_InvalidateFlags((1u << X86State::RFLAG_PF_RAW_LOC) | (1u << X86State::RFLAG_AF_RAW_LOC));
|
||||
InvalidateReg(Core::CPUState::PF_AS_GREG);
|
||||
InvalidateReg(Core::CPUState::AF_AS_GREG);
|
||||
}
|
||||
|
||||
CondClassType CondForNZCVBit(unsigned BitOffset, bool Invert) {
|
||||
@@ -1746,8 +1793,114 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void FlushRegisterCache() {
|
||||
CalculateDeferredFlags();
|
||||
/* Layout of cache indices. We use a single 64-bit bitmask for the cache */
|
||||
static const int GPR0Index = 0;
|
||||
static const int GPR15Index = 15;
|
||||
static const int PFIndex = 16;
|
||||
static const int AFIndex = 17;
|
||||
/* Gap 18..19 */
|
||||
static const int MM0Index = 20;
|
||||
static const int MM7Index = 27;
|
||||
static const int AbridgedFTWIndex = 28;
|
||||
/* Gap 29..30 */
|
||||
static const int DFIndex = 31;
|
||||
static const int FPR0Index = 32;
|
||||
static const int FPR15Index = 47;
|
||||
static const int AVXHigh0Index = 48;
|
||||
static const int AVXHigh15Index = 63;
|
||||
|
||||
int CacheIndexToContextOffset(int Index) {
|
||||
switch (Index) {
|
||||
case MM0Index ... MM7Index: return offsetof(FEXCore::Core::CPUState, mm[Index - MM0Index]);
|
||||
case AVXHigh0Index ... AVXHigh15Index: return offsetof(FEXCore::Core::CPUState, avx_high[Index - AVXHigh0Index][0]);
|
||||
case AbridgedFTWIndex: return offsetof(FEXCore::Core::CPUState, AbridgedFTW);
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
RegisterClassType CacheIndexClass(int Index) {
|
||||
if ((Index >= MM0Index && Index <= MM7Index) || Index >= FPR0Index) {
|
||||
return FPRClass;
|
||||
} else {
|
||||
return GPRClass;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned CacheIndexToSize(int Index) {
|
||||
if (Index >= AVXHigh0Index) {
|
||||
return 16;
|
||||
} else if (Index <= MM7Index) {
|
||||
return 8;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
uint64_t Cached;
|
||||
uint64_t Written;
|
||||
Ref Value[64];
|
||||
} RegCache {};
|
||||
|
||||
void InvalidateReg(uint8_t Index) {
|
||||
uint64_t Bit = (1ull << (uint64_t)Index);
|
||||
RegCache.Cached &= ~Bit;
|
||||
RegCache.Written &= ~Bit;
|
||||
}
|
||||
|
||||
Ref LoadRegCache(uint64_t Offset, uint8_t Index, RegisterClassType RegClass, uint8_t Size) {
|
||||
LOGMAN_THROW_AA_FMT(Index < 64, "valid index");
|
||||
uint64_t Bit = (1ull << (uint64_t)Index);
|
||||
|
||||
if (!(RegCache.Cached & Bit)) {
|
||||
if (Index == DFIndex) {
|
||||
RegCache.Value[Index] = _LoadDF();
|
||||
} else if ((Index >= MM0Index && Index <= AbridgedFTWIndex) || Index >= AVXHigh0Index) {
|
||||
RegCache.Value[Index] = _LoadContext(Size, RegClass, Offset);
|
||||
} else {
|
||||
RegCache.Value[Index] = _LoadRegister(Offset, RegClass, Size);
|
||||
}
|
||||
|
||||
RegCache.Cached |= Bit;
|
||||
}
|
||||
|
||||
return RegCache.Value[Index];
|
||||
}
|
||||
|
||||
Ref LoadGPR(uint8_t Reg) {
|
||||
return LoadRegCache(Reg, GPR0Index + Reg, GPRClass, CTX->GetGPRSize());
|
||||
}
|
||||
|
||||
Ref LoadContext(uint8_t Index) {
|
||||
return LoadRegCache(CacheIndexToContextOffset(Index), Index, CacheIndexClass(Index), CacheIndexToSize(Index));
|
||||
}
|
||||
|
||||
Ref LoadXMMRegister(uint8_t Reg) {
|
||||
const auto Size = CTX->HostFeatures.SupportsSVE256 ? 32 : 16;
|
||||
return LoadRegCache(Reg, FPR0Index + Reg, FPRClass, Size);
|
||||
}
|
||||
|
||||
Ref LoadDF() {
|
||||
return LoadGPR(DFIndex);
|
||||
}
|
||||
|
||||
void StoreContext(uint8_t Index, Ref Value) {
|
||||
LOGMAN_THROW_AA_FMT(Index < 64, "valid index");
|
||||
LOGMAN_THROW_AA_FMT(Value != InvalidNode, "storing valid");
|
||||
|
||||
uint64_t Bit = (1ull << (uint64_t)Index);
|
||||
|
||||
RegCache.Value[Index] = Value;
|
||||
RegCache.Cached |= Bit;
|
||||
RegCache.Written |= Bit;
|
||||
}
|
||||
|
||||
void StoreRegister(uint8_t Reg, bool FPR, Ref Value) {
|
||||
StoreContext(Reg + (FPR ? FPR0Index : GPR0Index), Value);
|
||||
}
|
||||
|
||||
void StoreDF(Ref Value) {
|
||||
StoreContext(DFIndex, Value);
|
||||
}
|
||||
|
||||
Ref GetRFLAG(unsigned BitOffset, bool Invert = false) {
|
||||
@@ -1766,12 +1919,12 @@ private:
|
||||
return _NZCVSelect(OpSize::i32Bit, CondForNZCVBit(BitOffset, Invert), _Constant(1), _Constant(0));
|
||||
}
|
||||
} else if (BitOffset == FEXCore::X86State::RFLAG_PF_RAW_LOC) {
|
||||
return _LoadRegister(Core::CPUState::PF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
return LoadGPR(Core::CPUState::PF_AS_GREG);
|
||||
} else if (BitOffset == FEXCore::X86State::RFLAG_AF_RAW_LOC) {
|
||||
return _LoadRegister(Core::CPUState::AF_AS_GREG, GPRClass, CTX->GetGPRSize());
|
||||
return LoadGPR(Core::CPUState::AF_AS_GREG);
|
||||
} else if (BitOffset == FEXCore::X86State::RFLAG_DF_RAW_LOC) {
|
||||
// Recover the sign bit, it is the logical DF value
|
||||
return _Lshr(OpSize::i64Bit, _LoadDF(), _Constant(63));
|
||||
return _Lshr(OpSize::i64Bit, LoadDF(), _Constant(63));
|
||||
} else {
|
||||
return _LoadFlag(BitOffset);
|
||||
}
|
||||
@@ -1779,7 +1932,7 @@ private:
|
||||
|
||||
// Returns (DF ? -Size : Size)
|
||||
Ref LoadDir(const unsigned Size) {
|
||||
auto Dir = _LoadDF();
|
||||
auto Dir = LoadDF();
|
||||
auto Shift = FEXCore::ilog2(Size);
|
||||
|
||||
if (Shift) {
|
||||
@@ -1793,7 +1946,7 @@ private:
|
||||
Ref OffsetByDir(Ref X, const unsigned Size) {
|
||||
auto Shift = FEXCore::ilog2(Size);
|
||||
|
||||
return _AddShift(OpSize::i64Bit, X, _LoadDF(), ShiftType::LSL, Shift);
|
||||
return _AddShift(OpSize::i64Bit, X, LoadDF(), ShiftType::LSL, Shift);
|
||||
}
|
||||
|
||||
// Compares two floats and sets flags for a COMISS instruction
|
||||
|
||||
@@ -530,17 +530,17 @@ void OpDispatchBuilder::AVX128_StoreResult_WithOpSize(FEXCore::X86Tables::Decode
|
||||
|
||||
Ref OpDispatchBuilder::AVX128_LoadXMMRegister(uint32_t XMM, bool High) {
|
||||
if (High) {
|
||||
return _LoadContext(16, FPRClass, offsetof(FEXCore::Core::CPUState, avx_high[XMM][0]));
|
||||
return LoadContext(AVXHigh0Index + XMM);
|
||||
} else {
|
||||
return _LoadRegister(XMM, FPRClass, 16);
|
||||
return LoadXMMRegister(XMM);
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::AVX128_StoreXMMRegister(uint32_t XMM, const Ref Src, bool High) {
|
||||
if (High) {
|
||||
_StoreContext(16, FPRClass, Src, offsetof(FEXCore::Core::CPUState, avx_high[XMM][0]));
|
||||
StoreContext(AVXHigh0Index + XMM, Src);
|
||||
} else {
|
||||
_StoreRegister(Src, XMM, FPRClass, 16);
|
||||
StoreXMMRegister(XMM, Src);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2644,8 +2644,7 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, Ref MemBase) {
|
||||
|
||||
{
|
||||
// Abridged FTW
|
||||
auto AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
_StoreMem(GPRClass, 1, AbridgedFTW, MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1);
|
||||
_StoreMem(GPRClass, 1, LoadContext(AbridgedFTWIndex), MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1);
|
||||
}
|
||||
|
||||
// BYTE | 0 1 | 2 3 | 4 | 5 | 6 7 | 8 9 | a b | c d | e f |
|
||||
@@ -2693,7 +2692,7 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, Ref MemBase) {
|
||||
// If OSFXSR bit in CR4 is not set than FXSAVE /may/ not save the XMM registers
|
||||
// This is implementation dependent
|
||||
for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) {
|
||||
Ref MMReg = _LoadContext(16, FPRClass, offsetof(FEXCore::Core::CPUState, mm[i]));
|
||||
Ref MMReg = LoadContext(MM0Index + i);
|
||||
|
||||
_StoreMem(FPRClass, 16, MMReg, MemBase, _Constant(i * 16 + 32), 16, MEM_OFFSET_SXTX, 1);
|
||||
}
|
||||
@@ -2820,13 +2819,12 @@ void OpDispatchBuilder::RestoreX87State(Ref MemBase) {
|
||||
|
||||
{
|
||||
// Abridged FTW
|
||||
auto NewAbridgedFTW = _LoadMem(GPRClass, 1, MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1);
|
||||
_StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
StoreContext(AbridgedFTWIndex, _LoadMem(GPRClass, 1, MemBase, _Constant(4), 2, MEM_OFFSET_SXTX, 1));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) {
|
||||
auto MMReg = _LoadMem(FPRClass, 16, MemBase, _Constant(i * 16 + 32), 16, MEM_OFFSET_SXTX, 1);
|
||||
_StoreContext(16, FPRClass, MMReg, offsetof(FEXCore::Core::CPUState, mm[i]));
|
||||
StoreContext(MM0Index + i, MMReg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2865,7 +2863,7 @@ void OpDispatchBuilder::DefaultX87State(OpcodeArgs) {
|
||||
// all of the ST0-7/MM0-7 registers to zero.
|
||||
Ref ZeroVector = LoadZeroVector(Core::CPUState::MM_REG_SIZE);
|
||||
for (uint32_t i = 0; i < Core::CPUState::NUM_MMS; ++i) {
|
||||
_StoreContext(16, FPRClass, ZeroVector, offsetof(FEXCore::Core::CPUState, mm[i]));
|
||||
StoreContext(MM0Index + i, ZeroVector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,14 +31,14 @@ Ref OpDispatchBuilder::GetX87Top() {
|
||||
|
||||
void OpDispatchBuilder::SetX87ValidTag(Ref Value, bool Valid) {
|
||||
// if we are popping then we must first mark this location as empty
|
||||
Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
Ref AbridgedFTW = LoadContext(AbridgedFTWIndex);
|
||||
Ref RegMask = _Lshl(OpSize::i32Bit, _Constant(1), Value);
|
||||
Ref NewAbridgedFTW = Valid ? _Or(OpSize::i32Bit, AbridgedFTW, RegMask) : _Andn(OpSize::i32Bit, AbridgedFTW, RegMask);
|
||||
_StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
StoreContext(AbridgedFTWIndex, NewAbridgedFTW);
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::GetX87ValidTag(Ref Value) {
|
||||
Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
Ref AbridgedFTW = LoadContext(AbridgedFTWIndex);
|
||||
return _And(OpSize::i32Bit, _Lshr(OpSize::i32Bit, AbridgedFTW, Value), _Constant(1));
|
||||
}
|
||||
|
||||
@@ -51,8 +51,7 @@ Ref OpDispatchBuilder::GetX87Tag(Ref Value, Ref AbridgedFTW) {
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::GetX87Tag(Ref Value) {
|
||||
Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
return GetX87Tag(Value, AbridgedFTW);
|
||||
return GetX87Tag(Value, LoadContext(AbridgedFTWIndex));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SetX87FTW(Ref FTW) {
|
||||
@@ -70,11 +69,11 @@ void OpDispatchBuilder::SetX87FTW(Ref FTW) {
|
||||
}
|
||||
}
|
||||
|
||||
_StoreContext(1, GPRClass, NewAbridgedFTW, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
StoreContext(AbridgedFTWIndex, NewAbridgedFTW);
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::GetX87FTW() {
|
||||
Ref AbridgedFTW = _LoadContext(1, GPRClass, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
Ref AbridgedFTW = LoadContext(AbridgedFTWIndex);
|
||||
Ref FTW = _Constant(0);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
@@ -154,7 +153,6 @@ void OpDispatchBuilder::FLD(OpcodeArgs) {
|
||||
SetX87Top(top);
|
||||
// Write to ST[TOP]
|
||||
_StoreContextIndexed(converted, top, 16, MMBaseOffset(), 16, FPRClass);
|
||||
//_StoreContext(converted, 16, offsetof(FEXCore::Core::CPUState, mm[7][0]));
|
||||
}
|
||||
|
||||
template void OpDispatchBuilder::FLD<32>(OpcodeArgs);
|
||||
@@ -644,7 +642,7 @@ void OpDispatchBuilder::FNINIT(OpcodeArgs) {
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(Zero);
|
||||
|
||||
// Tags all get marked as invalid
|
||||
_StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
StoreContext(AbridgedFTWIndex, Zero);
|
||||
}
|
||||
|
||||
template<size_t width, bool Integer, OpDispatchBuilder::FCOMIFlags whichflags, bool poptwice>
|
||||
@@ -1215,7 +1213,7 @@ void OpDispatchBuilder::X87FCMOV(OpcodeArgs) {
|
||||
|
||||
void OpDispatchBuilder::X87EMMS(OpcodeArgs) {
|
||||
// Tags all get set to 0b11
|
||||
_StoreContext(1, GPRClass, _Constant(0), offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
StoreContext(AbridgedFTWIndex, _Constant(0));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87FFREE(OpcodeArgs) {
|
||||
|
||||
@@ -60,7 +60,7 @@ void OpDispatchBuilder::FNINITF64(OpcodeArgs) {
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(Zero);
|
||||
|
||||
// Tags all get marked as invalid
|
||||
_StoreContext(1, GPRClass, Zero, offsetof(FEXCore::Core::CPUState, AbridgedFTW));
|
||||
StoreContext(AbridgedFTWIndex, Zero);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87LDENVF64(OpcodeArgs) {
|
||||
|
||||
Reference in new issue
Block a user