mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-12 06:00:39 +02:00
Merge pull request #4719 from Sonicadvance1/runtime_mode_switch_take2
Runtime mode switch take 2
This commit is contained in:
62 files changed
+18020
-17889
No files matched your search
@@ -290,10 +290,6 @@ public:
|
||||
uintptr_t CompileBlock(FEXCore::Core::CpuStateFrame* Frame, uint64_t GuestRIP, uint64_t MaxInst = 0);
|
||||
uintptr_t CompileSingleStep(FEXCore::Core::CpuStateFrame* Frame, uint64_t GuestRIP);
|
||||
|
||||
IR::OpSize GetGPROpSize() const {
|
||||
return Config.Is64BitMode ? IR::OpSize::i64Bit : IR::OpSize::i32Bit;
|
||||
}
|
||||
|
||||
FEXCore::JITSymbols Symbols;
|
||||
|
||||
FEXCore::Utils::PooledAllocatorVirtual OpDispatcherAllocator;
|
||||
|
||||
@@ -441,6 +441,22 @@ ContextImpl::CreateThread(uint64_t InitialRIP, uint64_t StackPointer, const FEXC
|
||||
Thread->CurrentFrame->State.gregs[X86State::REG_RSP] = StackPointer;
|
||||
Thread->CurrentFrame->State.rip = InitialRIP;
|
||||
|
||||
// Set up default code segment.
|
||||
// Default code segment indexes match the numbers that the Linux kernel uses.
|
||||
Thread->CurrentFrame->State.cs_idx = 6 << 3;
|
||||
auto &GDT = Thread->CurrentFrame->State.gdt[Thread->CurrentFrame->State.cs_idx >> 3];
|
||||
Thread->CurrentFrame->State.SetGDTBase(&GDT, 0);
|
||||
Thread->CurrentFrame->State.SetGDTLimit(&GDT, 0xF'FFFFU);
|
||||
|
||||
if (Config.Is64BitMode) {
|
||||
GDT.L = 1; // L = Long Mode = 64-bit
|
||||
GDT.D = 0; // D = Default Operand SIze = Reserved
|
||||
}
|
||||
else {
|
||||
GDT.L = 0; // L = Long Mode = 32-bit
|
||||
GDT.D = 1; // D = Default Operand Size = 32-bit
|
||||
}
|
||||
|
||||
// Copy over the new thread state to the new object
|
||||
if (NewThreadState) {
|
||||
memcpy(&Thread->CurrentFrame->State, NewThreadState, sizeof(FEXCore::Core::CPUState));
|
||||
@@ -558,14 +574,14 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue
|
||||
bool HadDispatchError {false};
|
||||
bool HadInvalidInst {false};
|
||||
|
||||
Thread->FrontendDecoder->DecodeInstructionsAtEntry(GuestCode, GuestRIP, MaxInst);
|
||||
Thread->FrontendDecoder->DecodeInstructionsAtEntry(Thread, GuestCode, GuestRIP, MaxInst);
|
||||
|
||||
auto BlockInfo = Thread->FrontendDecoder->GetDecodedBlockInfo();
|
||||
auto CodeBlocks = &BlockInfo->Blocks;
|
||||
|
||||
Thread->OpDispatcher->BeginFunction(GuestRIP, CodeBlocks, BlockInfo->TotalInstructionCount);
|
||||
Thread->OpDispatcher->BeginFunction(GuestRIP, CodeBlocks, BlockInfo->TotalInstructionCount, BlockInfo->Is64BitMode);
|
||||
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto GPRSize = Thread->OpDispatcher->GetGPROpSize();
|
||||
|
||||
for (size_t j = 0; j < CodeBlocks->size(); ++j) {
|
||||
const FEXCore::Frontend::Decoder::DecodedBlocks& Block = CodeBlocks->at(j);
|
||||
@@ -1021,7 +1037,7 @@ void ContextImpl::AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t Gu
|
||||
IRHeader.first->Blocks = emit->WrapNode(Block);
|
||||
emit->SetCurrentCodeBlock(Block);
|
||||
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto GPRSize = this->Config.Is64BitMode ? IR::OpSize::i64Bit : IR::OpSize::i32Bit;
|
||||
|
||||
if (GPRSize == IR::OpSize::i64Bit) {
|
||||
IR::Ref R = emit->_StoreRegister(emit->Constant(Entrypoint), GPRSize);
|
||||
|
||||
@@ -333,7 +333,7 @@ bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op,
|
||||
uint8_t DestSize {};
|
||||
const bool HasWideningDisplacement =
|
||||
(FEXCore::X86Tables::DecodeFlags::GetOpAddr(DecodeInst->Flags, 0) & FEXCore::X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST) != 0 ||
|
||||
(Options.w && CTX->Config.Is64BitMode);
|
||||
(Options.w && BlockInfo.Is64BitMode);
|
||||
const bool HasNarrowingDisplacement =
|
||||
(FEXCore::X86Tables::DecodeFlags::GetOpAddr(DecodeInst->Flags, 0) & FEXCore::X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST) != 0;
|
||||
|
||||
@@ -351,7 +351,7 @@ bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op,
|
||||
const bool HasMODRM = !!(Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_MODRM);
|
||||
|
||||
const bool HasREX = !!(DecodeInst->Flags & DecodeFlags::FLAG_REX_PREFIX);
|
||||
const bool Has16BitAddressing = !CTX->Config.Is64BitMode && DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
const bool Has16BitAddressing = !BlockInfo.Is64BitMode && DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
|
||||
if (Options.w && (Info->Flags & InstFlags::FLAGS_REX_W_0)) {
|
||||
return false;
|
||||
@@ -412,7 +412,7 @@ bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op,
|
||||
// If the default operating mode is 32bit and we have the operand size flag then the operating size drops to 16bit
|
||||
DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_16BIT);
|
||||
DestSize = 2;
|
||||
} else if ((HasXMMDst || HasMMDst || CTX->Config.Is64BitMode) &&
|
||||
} else if ((HasXMMDst || HasMMDst || BlockInfo.Is64BitMode) &&
|
||||
(HasWideningDisplacement || DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BIT ||
|
||||
DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) {
|
||||
DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_64BIT);
|
||||
@@ -441,7 +441,7 @@ bool Decoder::NormalOp(const FEXCore::X86Tables::X86InstInfo* Info, uint16_t Op,
|
||||
// See table 1-2. Operand-Size Overrides for this decoding
|
||||
// If the default operating mode is 32bit and we have the operand size flag then the operating size drops to 16bit
|
||||
DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_16BIT);
|
||||
} else if ((HasXMMSrc || HasMMSrc || CTX->Config.Is64BitMode) &&
|
||||
} else if ((HasXMMSrc || HasMMSrc || BlockInfo.Is64BitMode) &&
|
||||
(HasWideningDisplacement || SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BIT ||
|
||||
SrcSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_64BITDEF)) {
|
||||
DecodeInst->Flags |= DecodeFlags::GenSizeSrcSize(DecodeFlags::SIZE_64BIT);
|
||||
@@ -711,7 +711,7 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16
|
||||
DecodedHeader options {};
|
||||
|
||||
if ((Byte1 & 0b10000000) == 0) {
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -730,12 +730,12 @@ bool Decoder::NormalOpHeader(const FEXCore::X86Tables::X86InstInfo* Info, uint16
|
||||
options.w = (Byte2 & 0b10000000) != 0;
|
||||
options.L = (Byte2 & 0b100) != 0;
|
||||
if ((Byte1 & 0b01000000) == 0) {
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
return false;
|
||||
}
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X;
|
||||
}
|
||||
if (CTX->Config.Is64BitMode && (Byte1 & 0b00100000) == 0) {
|
||||
if (BlockInfo.Is64BitMode && (Byte1 & 0b00100000) == 0) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B;
|
||||
}
|
||||
if (options.w) {
|
||||
@@ -808,7 +808,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) {
|
||||
FEXCore::X86Tables::ModRMDecoded ModRM;
|
||||
ModRM.Hex = DecodeInst->ModRM;
|
||||
|
||||
const bool Has16BitAddressing = !CTX->Config.Is64BitMode && DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
const bool Has16BitAddressing = !BlockInfo.Is64BitMode && DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
|
||||
// All 3DNow! instructions have the second argument as the rm handler
|
||||
// We need to decode it upfront to get the displacement out of the way
|
||||
@@ -917,17 +917,17 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
break;
|
||||
case 0x26: // ES legacy prefix
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_ES_PREFIX;
|
||||
}
|
||||
break;
|
||||
case 0x2E: // CS legacy prefix
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_CS_PREFIX;
|
||||
}
|
||||
break;
|
||||
case 0x36: // SS legacy prefix
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_SS_PREFIX;
|
||||
}
|
||||
break;
|
||||
@@ -935,7 +935,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) {
|
||||
// Annoyingly GCC generates NOP ops with these prefixes
|
||||
// Just ignore them for now
|
||||
// eg. 66 2e 0f 1f 84 00 00 00 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_DS_PREFIX;
|
||||
}
|
||||
break;
|
||||
@@ -962,7 +962,7 @@ bool Decoder::DecodeInstructionImpl(uint64_t PC) {
|
||||
auto Info = &FEXCore::X86Tables::BaseOps[Op];
|
||||
|
||||
if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) {
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!BlockInfo.Is64BitMode) {
|
||||
return false;
|
||||
}
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX;
|
||||
@@ -1029,7 +1029,7 @@ void Decoder::BranchTargetInMultiblockRange() {
|
||||
|
||||
// If the RIP setting is conditional AND within our symbol range then it can be considered for multiblock
|
||||
uint64_t TargetRIP = 0;
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
bool Conditional = true;
|
||||
const auto InstEnd = DecodeInst->PC + DecodeInst->InstSize;
|
||||
|
||||
@@ -1102,7 +1102,7 @@ bool Decoder::InstCanContinue() const {
|
||||
}
|
||||
|
||||
uint64_t TargetRIP = 0;
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
if (DecodeInst->OP == 0xE8) { // Call - immediate target
|
||||
const uint64_t NextRIP = DecodeInst->PC + DecodeInst->InstSize;
|
||||
@@ -1194,7 +1194,7 @@ const uint8_t* Decoder::AdjustAddrForSpecialRegion(const uint8_t* _InstStream, u
|
||||
return _InstStream - EntryPoint + RIP;
|
||||
}
|
||||
|
||||
void Decoder::DecodeInstructionsAtEntry(const uint8_t* _InstStream, uint64_t PC, uint64_t MaxInst) {
|
||||
void Decoder::DecodeInstructionsAtEntry(FEXCore::Core::InternalThreadState *Thread, const uint8_t* _InstStream, uint64_t PC, uint64_t MaxInst) {
|
||||
FEXCORE_PROFILE_SCOPED("DecodeInstructions");
|
||||
BlockInfo.TotalInstructionCount = 0;
|
||||
BlockInfo.Blocks.clear();
|
||||
@@ -1205,6 +1205,11 @@ void Decoder::DecodeInstructionsAtEntry(const uint8_t* _InstStream, uint64_t PC,
|
||||
MaxCondBranchBackwards = ~0ULL;
|
||||
DecodedBuffer = PoolObject.ReownOrClaimBuffer();
|
||||
|
||||
// Decode operating mode from thread's CS segment.
|
||||
const auto CSSegment = Thread->CurrentFrame->State.gdt[Thread->CurrentFrame->State.cs_idx >> 3];
|
||||
BlockInfo.Is64BitMode = CSSegment.L == 1;
|
||||
LOGMAN_THROW_A_FMT(BlockInfo.Is64BitMode == CTX->Config.Is64BitMode, "Expected operating mode to not change at runtime!");
|
||||
|
||||
// XXX: Load symbol data
|
||||
SymbolAvailable = false;
|
||||
EntryPoint = PC;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Interface/Core/X86Tables/X86Tables.h"
|
||||
#include "Interface/IR/IR.h"
|
||||
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
#include <FEXCore/Utils/Telemetry.h>
|
||||
@@ -37,13 +38,14 @@ public:
|
||||
|
||||
struct DecodedBlockInformation final {
|
||||
uint64_t TotalInstructionCount;
|
||||
bool Is64BitMode {};
|
||||
fextl::vector<DecodedBlocks> Blocks;
|
||||
fextl::set<uint64_t> EntryPoints;
|
||||
fextl::set<uint64_t> CodePages; // Start addresses of all pages touching the block
|
||||
};
|
||||
|
||||
Decoder(FEXCore::Core::InternalThreadState* Thread);
|
||||
void DecodeInstructionsAtEntry(const uint8_t* InstStream, uint64_t PC, uint64_t MaxInst);
|
||||
void DecodeInstructionsAtEntry(FEXCore::Core::InternalThreadState *Thread, const uint8_t* InstStream, uint64_t PC, uint64_t MaxInst);
|
||||
|
||||
const DecodedBlockInformation* GetDecodedBlockInfo() const {
|
||||
return &BlockInfo;
|
||||
@@ -110,6 +112,9 @@ private:
|
||||
bool HitNonExecutableRange {};
|
||||
|
||||
const uint8_t* InstStream {};
|
||||
IR::OpSize GetGPROpSize() const {
|
||||
return BlockInfo.Is64BitMode ? IR::OpSize::i64Bit : IR::OpSize::i32Bit;
|
||||
}
|
||||
|
||||
static constexpr size_t MAX_INST_SIZE = 15;
|
||||
uint8_t InstructionSize {};
|
||||
|
||||
@@ -72,7 +72,7 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs, bool IsSyscallInst) {
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
auto NewRIP = GetRelocatedPC(Op, -Op->InstSize);
|
||||
_StoreContext(GPRSize, GPRClass, NewRIP, offsetof(FEXCore::Core::CPUState, rip));
|
||||
|
||||
@@ -112,10 +112,10 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs, bool IsSyscallInst) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::ThunkOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
uint8_t* sha256 = (uint8_t*)(Op->PC + 2);
|
||||
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
// x86-64 ABI puts the function argument in RDI
|
||||
Thunk(LoadGPRRegister(X86State::REG_RDI), *reinterpret_cast<SHA256Sum*>(sha256));
|
||||
} else {
|
||||
@@ -134,7 +134,7 @@ void OpDispatchBuilder::LEAOp(OpcodeArgs) {
|
||||
// LEA specifically ignores segment prefixes
|
||||
const auto SrcSize = OpSizeFromSrc(Op);
|
||||
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
const auto DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? OpSize::i16Bit :
|
||||
X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? OpSize::i64Bit :
|
||||
OpSize::i32Bit;
|
||||
@@ -153,7 +153,7 @@ void OpDispatchBuilder::LEAOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::NOPOp(OpcodeArgs) {}
|
||||
|
||||
void OpDispatchBuilder::RETOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
// ABI Optimization: Flags don't survive calls or rets
|
||||
if (CTX->Config.ABILocalFlags) {
|
||||
@@ -194,7 +194,7 @@ void OpDispatchBuilder::IRETOp(OpcodeArgs) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
Ref SP = _RMWHandle(LoadGPRRegister(X86State::REG_RSP));
|
||||
|
||||
@@ -208,7 +208,7 @@ void OpDispatchBuilder::IRETOp(OpcodeArgs) {
|
||||
// eflags (lower 16 used)
|
||||
SetPackedRFLAG(false, Pop(GPRSize, SP));
|
||||
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
// RSP and SS only happen in 64-bit mode or if this is a CPL mode jump!
|
||||
// FEX doesn't support a CPL mode switch, so don't need to worry about this on 32-bit
|
||||
StoreGPRRegister(X86State::REG_RSP, Pop(GPRSize, SP));
|
||||
@@ -227,7 +227,7 @@ void OpDispatchBuilder::IRETOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CallbackReturnOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
// Store the new RIP
|
||||
_CallbackReturn();
|
||||
auto NewRIP = _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, rip));
|
||||
@@ -385,7 +385,7 @@ void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs, uint32_t SegmentReg) {
|
||||
const auto DstSize = OpSizeFromDst(Op);
|
||||
|
||||
Ref Src {};
|
||||
if (!CTX->Config.Is64BitMode()) {
|
||||
if (!Is64BitMode) {
|
||||
switch (SegmentReg) {
|
||||
case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX:
|
||||
Src = _LoadContext(SrcSize, GPRClass, offsetof(FEXCore::Core::CPUState, es_idx));
|
||||
@@ -510,7 +510,7 @@ void OpDispatchBuilder::LEAVEOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CALLOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
BlockSetRIP = true;
|
||||
|
||||
@@ -673,7 +673,7 @@ void OpDispatchBuilder::SETccOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CMOVOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
@@ -703,7 +703,7 @@ void OpDispatchBuilder::CondJUMPOp(OpcodeArgs) {
|
||||
uint64_t InstRIP = Op->PC + Op->InstSize;
|
||||
uint64_t Target = InstRIP + TargetOffset;
|
||||
|
||||
if (CTX->GetGPROpSize() == OpSize::i32Bit) {
|
||||
if (GetGPROpSize() == OpSize::i32Bit) {
|
||||
// If the GPRSize is 4 then we need to be careful about PC wrapping
|
||||
if (TargetOffset < 0 && -TargetOffset > InstRIP) {
|
||||
// Invert the signed value if we are underflowing
|
||||
@@ -773,7 +773,7 @@ void OpDispatchBuilder::CondJUMPRCXOp(OpcodeArgs) {
|
||||
CalculateDeferredFlags();
|
||||
|
||||
BlockSetRIP = true;
|
||||
auto JcxGPRSize = CTX->GetGPROpSize();
|
||||
auto JcxGPRSize = GetGPROpSize();
|
||||
JcxGPRSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) ? (JcxGPRSize >> 1) : JcxGPRSize;
|
||||
|
||||
uint64_t Target = Op->PC + Op->InstSize + Op->Src[0].Literal();
|
||||
@@ -835,7 +835,7 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) {
|
||||
auto SrcSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) ? OpSize::i32Bit : OpSize::i64Bit;
|
||||
auto OpSize = SrcSize == OpSize::i64Bit ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
// RCX size is 32-bit or 16-bit when executing in 32-bit mode.
|
||||
SrcSize = IR::SizeToOpSize(IR::OpSizeToSize(SrcSize) >> 1);
|
||||
OpSize = OpSize::i32Bit;
|
||||
@@ -909,7 +909,7 @@ void OpDispatchBuilder::JUMPOp(OpcodeArgs) {
|
||||
uint64_t InstRIP = Op->PC + Op->InstSize;
|
||||
uint64_t TargetRIP = InstRIP + TargetOffset;
|
||||
|
||||
if (CTX->GetGPROpSize() == OpSize::i32Bit) {
|
||||
if (GetGPROpSize() == OpSize::i32Bit) {
|
||||
// If the GPRSize is 4 then we need to be careful about PC wrapping
|
||||
if (TargetOffset < 0 && -TargetOffset > InstRIP) {
|
||||
// Invert the signed value if we are underflowing
|
||||
@@ -1208,7 +1208,7 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs, bool ToSeg) {
|
||||
break;
|
||||
case FEXCore::X86State::REG_RBP: // GS
|
||||
case FEXCore::X86State::REG_R13: // GS
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
_StoreContext(OpSize::i16Bit, GPRClass, Src, offsetof(FEXCore::Core::CPUState, gs_idx));
|
||||
UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX);
|
||||
} else {
|
||||
@@ -1218,7 +1218,7 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs, bool ToSeg) {
|
||||
break;
|
||||
case FEXCore::X86State::REG_RSP: // FS
|
||||
case FEXCore::X86State::REG_R12: // FS
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
_StoreContext(OpSize::i16Bit, GPRClass, Src, offsetof(FEXCore::Core::CPUState, fs_idx));
|
||||
UpdatePrefixFromSegment(Src, FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX);
|
||||
} else {
|
||||
@@ -1253,7 +1253,7 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs, bool ToSeg) {
|
||||
break;
|
||||
case FEXCore::X86State::REG_RBP: // GS
|
||||
case FEXCore::X86State::REG_R13: // GS
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
Segment = Constant(0);
|
||||
} else {
|
||||
Segment = _LoadContext(OpSize::i16Bit, GPRClass, offsetof(FEXCore::Core::CPUState, gs_idx));
|
||||
@@ -1261,7 +1261,7 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs, bool ToSeg) {
|
||||
break;
|
||||
case FEXCore::X86State::REG_RSP: // FS
|
||||
case FEXCore::X86State::REG_R12: // FS
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
Segment = Constant(0);
|
||||
} else {
|
||||
Segment = _LoadContext(OpSize::i16Bit, GPRClass, offsetof(FEXCore::Core::CPUState, fs_idx));
|
||||
@@ -1306,7 +1306,7 @@ void OpDispatchBuilder::MOVOffsetOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CPUIDOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
Ref Src = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], GPRSize, Op->Flags);
|
||||
Ref Leaf = LoadGPRRegister(X86State::REG_RCX);
|
||||
@@ -1736,7 +1736,7 @@ void OpDispatchBuilder::BLSRBMIOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::BMI2Shift(OpcodeArgs) {
|
||||
// In the event the source is a memory operand, use the
|
||||
// exact width instead of the GPR size.
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto Size = OpSizeFromSrc(Op);
|
||||
const auto SrcSize = Op->Src[0].IsGPR() ? GPRSize : Size;
|
||||
|
||||
@@ -1797,7 +1797,7 @@ void OpDispatchBuilder::RORX(OpcodeArgs) {
|
||||
const auto SrcSize = OpSizeFromSrc(Op);
|
||||
const auto SrcSizeBits = IR::OpSizeAsBits(SrcSize);
|
||||
const auto Amount = Op->Src[1].Literal() & (SrcSizeBits - 1);
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
const auto DoRotation = Amount != 0 && Amount < SrcSizeBits;
|
||||
const auto IsSameGPR = Op->Src[0].IsGPR() && Op->Dest.IsGPR() && Op->Src[0].Data.GPR.GPR == Op->Dest.Data.GPR.GPR;
|
||||
@@ -1828,7 +1828,7 @@ void OpDispatchBuilder::MULX(OpcodeArgs) {
|
||||
|
||||
// Src1 can be a memory operand, so ensure we constrain to the
|
||||
// absolute width of the access in that scenario.
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto Src1Size = Op->Src[1].IsGPR() ? GPRSize : OpSize;
|
||||
|
||||
Ref Src1 = LoadSource_WithOpSize(GPRClass, Op, Op->Src[1], Src1Size, Op->Flags);
|
||||
@@ -2353,7 +2353,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) {
|
||||
if (Op->Dest.IsGPR()) {
|
||||
// When the destination is a GPR, we don't care about garbage in the upper bits.
|
||||
// Load the full register.
|
||||
auto Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GetGPROpSize(), Op->Flags);
|
||||
Value = Dest;
|
||||
|
||||
// Get the bit selection from the src. We need to mask for 8/16-bit, but
|
||||
@@ -2436,7 +2436,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) {
|
||||
|
||||
if (DestIsLockedMem(Op)) {
|
||||
HandledLock = true;
|
||||
Value = _AtomicFetchCLR(OpSize::i8Bit, BitMask, LoadEffectiveAddress(this, Address, CTX->GetGPROpSize(), true));
|
||||
Value = _AtomicFetchCLR(OpSize::i8Bit, BitMask, LoadEffectiveAddress(this, Address, GetGPROpSize(), true));
|
||||
} else {
|
||||
Value = _LoadMemAutoTSO(GPRClass, OpSize::i8Bit, Address, OpSize::i8Bit);
|
||||
|
||||
@@ -2451,7 +2451,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) {
|
||||
|
||||
if (DestIsLockedMem(Op)) {
|
||||
HandledLock = true;
|
||||
Value = _AtomicFetchOr(OpSize::i8Bit, BitMask, LoadEffectiveAddress(this, Address, CTX->GetGPROpSize(), true));
|
||||
Value = _AtomicFetchOr(OpSize::i8Bit, BitMask, LoadEffectiveAddress(this, Address, GetGPROpSize(), true));
|
||||
} else {
|
||||
Value = _LoadMemAutoTSO(GPRClass, OpSize::i8Bit, Address, OpSize::i8Bit);
|
||||
|
||||
@@ -2466,7 +2466,7 @@ void OpDispatchBuilder::BTOp(OpcodeArgs, uint32_t SrcIndex, BTAction Action) {
|
||||
|
||||
if (DestIsLockedMem(Op)) {
|
||||
HandledLock = true;
|
||||
Value = _AtomicFetchXor(OpSize::i8Bit, BitMask, LoadEffectiveAddress(this, Address, CTX->GetGPROpSize(), true));
|
||||
Value = _AtomicFetchXor(OpSize::i8Bit, BitMask, LoadEffectiveAddress(this, Address, GetGPROpSize(), true));
|
||||
} else {
|
||||
Value = _LoadMemAutoTSO(GPRClass, OpSize::i8Bit, Address, OpSize::i8Bit);
|
||||
|
||||
@@ -2601,7 +2601,7 @@ void OpDispatchBuilder::IMULOp(OpcodeArgs) {
|
||||
StoreGPRRegister(X86State::REG_RAX, LocalResult);
|
||||
StoreGPRRegister(X86State::REG_RDX, LocalResultHigh);
|
||||
} else if (Size == OpSize::i64Bit) {
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
LogMan::Msg::EFmt("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
@@ -2650,7 +2650,7 @@ void OpDispatchBuilder::MULOp(OpcodeArgs) {
|
||||
StoreGPRRegister(X86State::REG_RAX, ResultLow);
|
||||
StoreGPRRegister(X86State::REG_RDX, ResultHigh);
|
||||
} else if (Size == OpSize::i64Bit) {
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
LogMan::Msg::EFmt("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
@@ -2701,7 +2701,7 @@ void OpDispatchBuilder::NOTOp(OpcodeArgs) {
|
||||
|
||||
// Always load full size, we explicitly want the upper bits to get the
|
||||
// insert behaviour for free/implicitly.
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
Ref Src = LoadSource_WithOpSize(GPRClass, Op, Dest, GPRSize, Op->Flags);
|
||||
|
||||
// For 8/16-bit, use 64-bit invert so we invert in place, while getting
|
||||
@@ -2910,14 +2910,14 @@ void OpDispatchBuilder::WriteSegmentReg(OpcodeArgs, OpDispatchBuilder::Segment S
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::EnterOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const uint64_t Value = Op->Src[0].Literal();
|
||||
|
||||
const uint16_t AllocSpace = Value & 0xFFFF;
|
||||
const uint8_t Level = (Value >> 16) & 0x1F;
|
||||
|
||||
const auto PushValue = [&](IR::OpSize Size, Ref Src) -> Ref {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
auto OldSP = LoadGPRRegister(X86State::REG_RSP);
|
||||
auto NewSP = _Push(GPRSize, Size, Src, OldSP);
|
||||
@@ -2958,7 +2958,7 @@ void OpDispatchBuilder::SGDTOp(OpcodeArgs) {
|
||||
// Operand size prefix is ignored on this instruction, size purely depends on operating mode.
|
||||
uint64_t GDTAddress = 0xFFFFFFFFFFFE0000ULL;
|
||||
auto GDTStoreSize = OpSize::i64Bit;
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
// Mask off upper bits if 32-bit result.
|
||||
GDTAddress &= ~0U;
|
||||
GDTStoreSize = OpSize::i32Bit;
|
||||
@@ -2974,7 +2974,7 @@ void OpDispatchBuilder::SIDTOp(OpcodeArgs) {
|
||||
// See SGDTOp, matches Linux in reported values
|
||||
uint64_t IDTAddress = 0xFFFFFE0000000000ULL;
|
||||
auto IDTStoreSize = OpSize::i64Bit;
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
if (!Is64BitMode) {
|
||||
// Mask off upper bits if 32-bit result.
|
||||
IDTAddress &= ~0U;
|
||||
IDTStoreSize = OpSize::i32Bit;
|
||||
@@ -3003,7 +3003,7 @@ void OpDispatchBuilder::SMSWOp(OpcodeArgs) {
|
||||
(1U << 1) | ///< MP - Monitor Coprocessor
|
||||
(1U << 0)); ///< PE - Protection Enabled
|
||||
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? OpSize::i16Bit :
|
||||
X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_WIDENING_SIZE_LAST ? OpSize::i64Bit :
|
||||
OpSize::i32Bit;
|
||||
@@ -3011,7 +3011,7 @@ void OpDispatchBuilder::SMSWOp(OpcodeArgs) {
|
||||
if (!IsMemDst && DstSize == OpSize::i32Bit) {
|
||||
// Special-case version of `smsw ebx`. This instruction does an insert in to the lower 32-bits on 64-bit hosts.
|
||||
// Override and insert.
|
||||
auto Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GetGPROpSize(), Op->Flags);
|
||||
Const = _Bfi(OpSize::i64Bit, 32, 0, Dest, Const);
|
||||
DstSize = OpSize::i64Bit;
|
||||
}
|
||||
@@ -3531,7 +3531,7 @@ void OpDispatchBuilder::BSWAPOp(OpcodeArgs) {
|
||||
// BSWAP of 16bit is undef. ZEN+ causes the lower 16bits to get zero'd
|
||||
Dest = Constant(0);
|
||||
} else {
|
||||
Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, CTX->GetGPROpSize(), Op->Flags);
|
||||
Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, GetGPROpSize(), Op->Flags);
|
||||
Dest = _Rev(Size, Dest);
|
||||
}
|
||||
StoreResult(GPRClass, Op, Dest, OpSize::iInvalid);
|
||||
@@ -3575,13 +3575,13 @@ void OpDispatchBuilder::NEGOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::DIVOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
// This loads the divisor. 32-bit/64-bit paths mask inside the JIT, 8/16 do not.
|
||||
Ref Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = Size >= OpSize::i32Bit});
|
||||
|
||||
if (Size == OpSize::i64Bit && !CTX->Config.Is64BitMode) {
|
||||
if (Size == OpSize::i64Bit && !Is64BitMode) {
|
||||
LogMan::Msg::EFmt("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
@@ -3619,10 +3619,10 @@ void OpDispatchBuilder::IDIVOp(OpcodeArgs) {
|
||||
// This loads the divisor
|
||||
Ref Divisor = LoadSource(GPRClass, Op, Op->Dest, Op->Flags);
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
if (Size == OpSize::i64Bit && !CTX->Config.Is64BitMode) {
|
||||
if (Size == OpSize::i64Bit && !Is64BitMode) {
|
||||
LogMan::Msg::EFmt("Doesn't exist in 32bit mode");
|
||||
DecodeFailure = true;
|
||||
return;
|
||||
@@ -3659,7 +3659,7 @@ void OpDispatchBuilder::IDIVOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::BSFOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto DstSize = OpSizeFromDst(Op) == OpSize::i16Bit ? OpSize::i16Bit : GPRSize;
|
||||
Ref Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, DstSize, Op->Flags, {.AllowUpperGarbage = true});
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true});
|
||||
@@ -3681,7 +3681,7 @@ void OpDispatchBuilder::BSFOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::BSROp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto DstSize = OpSizeFromDst(Op) == OpSize::i16Bit ? OpSize::i16Bit : GPRSize;
|
||||
Ref Dest = LoadSource_WithOpSize(GPRClass, Op, Op->Dest, DstSize, Op->Flags, {.AllowUpperGarbage = true});
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true});
|
||||
@@ -3714,7 +3714,7 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) {
|
||||
// *Xn = Xt
|
||||
// Xs = MemData
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
auto Size = OpSizeFromSrc(Op);
|
||||
|
||||
if (Op->Dest.IsGPR()) {
|
||||
@@ -3858,8 +3858,10 @@ void OpDispatchBuilder::CreateJumpBlocks(const fextl::vector<FEXCore::Frontend::
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::BeginFunction(uint64_t RIP, const fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks>* Blocks, uint32_t NumInstructions) {
|
||||
void OpDispatchBuilder::BeginFunction(uint64_t RIP, const fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks>* Blocks, uint32_t NumInstructions, bool _Is64BitMode) {
|
||||
Entry = RIP;
|
||||
Is64BitMode = _Is64BitMode;
|
||||
LOGMAN_THROW_A_FMT(Is64BitMode == CTX->Config.Is64BitMode, "Expected operating mode to not change at runtime!");
|
||||
auto IRHeader = _IRHeader(InvalidNode, RIP, 0, NumInstructions, 0, 0);
|
||||
CreateJumpBlocks(Blocks);
|
||||
|
||||
@@ -3872,7 +3874,7 @@ void OpDispatchBuilder::BeginFunction(uint64_t RIP, const fextl::vector<FEXCore:
|
||||
void OpDispatchBuilder::Finalize() {
|
||||
// This usually doesn't emit any IR but in the case of hitting the block instruction limit it will
|
||||
FlushRegisterCache();
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
// Node 0 is invalid node
|
||||
Ref RealNode = reinterpret_cast<Ref>(GetNode(1));
|
||||
@@ -3913,9 +3915,9 @@ uint32_t OpDispatchBuilder::GetDstBitSize(X86Tables::DecodedOp Op) const {
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::GetSegment(uint32_t Flags, uint32_t DefaultPrefix, bool Override) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
if (Flags & FEXCore::X86Tables::DecodeFlags::FLAG_FS_PREFIX) {
|
||||
return _LoadContext(GPRSize, GPRClass, offsetof(FEXCore::Core::CPUState, fs_cached));
|
||||
} else if (Flags & FEXCore::X86Tables::DecodeFlags::FLAG_GS_PREFIX) {
|
||||
@@ -4055,8 +4057,15 @@ void OpDispatchBuilder::UpdatePrefixFromSegment(Ref Segment, uint32_t SegmentReg
|
||||
// Use BFE to extract the selector index in bits [15,3] of the segment register.
|
||||
// In some cases the upper 16-bits of the 32-bit GPR contain garbage to ignore.
|
||||
Segment = _Bfe(OpSize::i32Bit, 16 - 3, 3, Segment);
|
||||
auto NewSegment = _LoadContextIndexed(Segment, OpSize::i32Bit, offsetof(FEXCore::Core::CPUState, gdt[0]), 4, GPRClass);
|
||||
Ref NewSegment = _LoadContextIndexed(Segment, OpSize::i64Bit, offsetof(FEXCore::Core::CPUState, gdt[0]), 8, GPRClass);
|
||||
CheckLegacySegmentWrite(NewSegment, SegmentReg);
|
||||
|
||||
// Extract the 32-bit base from the GDT segment.
|
||||
auto Upper32 = _Lshr(OpSize::i64Bit, NewSegment, _Constant(32));
|
||||
auto Masked = _And(OpSize::i32Bit, Upper32, _Constant(0xFF00'0000));
|
||||
Ref Merged = _Orlshr(OpSize::i32Bit, Masked, NewSegment, 16);
|
||||
NewSegment = _Bfi(OpSize::i32Bit, 8, 16, Merged, Upper32);
|
||||
|
||||
switch (SegmentReg) {
|
||||
case FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX:
|
||||
_StoreContext(OpSize::i32Bit, GPRClass, NewSegment, offsetof(FEXCore::Core::CPUState, es_cached));
|
||||
@@ -4082,7 +4091,7 @@ void OpDispatchBuilder::UpdatePrefixFromSegment(Ref Segment, uint32_t SegmentReg
|
||||
|
||||
AddressMode OpDispatchBuilder::DecodeAddress(const X86Tables::DecodedOp& Op, const X86Tables::DecodedOperand& Operand,
|
||||
MemoryAccessType AccessType, bool IsLoad) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
AddressMode A {};
|
||||
A.Segment = GetSegment(Op->Flags);
|
||||
@@ -4108,7 +4117,7 @@ AddressMode OpDispatchBuilder::DecodeAddress(const X86Tables::DecodedOp& Op, con
|
||||
A.Offset = Operand.Data.GPRIndirect.Displacement;
|
||||
A.NonTSO |= IsNonTSOReg(AccessType, Operand.Data.GPRIndirect.GPR);
|
||||
} else if (Operand.IsRIPRelative()) {
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
if (Is64BitMode) {
|
||||
A.Base = GetRelocatedPC(Op, Operand.Data.RIPLiteral.Value.s);
|
||||
} else {
|
||||
// 32bit this isn't RIP relative but instead absolute
|
||||
@@ -4177,7 +4186,7 @@ Ref OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86T
|
||||
|
||||
if ((IsOperandMem(Operand, true) && LoadData) || ForceLoad) {
|
||||
if (OpSize == OpSize::f80Bit) {
|
||||
Ref MemSrc = LoadEffectiveAddress(this, A, CTX->GetGPROpSize(), true);
|
||||
Ref MemSrc = LoadEffectiveAddress(this, A, GetGPROpSize(), true);
|
||||
if (CTX->HostFeatures.SupportsSVE128 || CTX->HostFeatures.SupportsSVE256) {
|
||||
return _LoadMemX87SVEOptPredicate(OpSize::i128Bit, OpSize::i16Bit, MemSrc);
|
||||
} else {
|
||||
@@ -4189,17 +4198,17 @@ Ref OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, const X86T
|
||||
|
||||
return _LoadMemAutoTSO(Class, OpSize, A, Align == OpSize::iInvalid ? OpSize : Align);
|
||||
} else {
|
||||
return LoadEffectiveAddress(this, A, CTX->GetGPROpSize(), false, AllowUpperGarbage);
|
||||
return LoadEffectiveAddress(this, A, GetGPROpSize(), false, AllowUpperGarbage);
|
||||
}
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::GetRelocatedPC(const FEXCore::X86Tables::DecodedOp& Op, int64_t Offset) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
return _EntrypointOffset(GPRSize, Op->PC + Op->InstSize + Offset - Entry);
|
||||
}
|
||||
|
||||
Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, IR::OpSize Size, uint8_t Offset, bool AllowUpperGarbage) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
if (Size == OpSize::iInvalid) {
|
||||
Size = GPRSize;
|
||||
}
|
||||
@@ -4218,7 +4227,7 @@ Ref OpDispatchBuilder::LoadGPRRegister(uint32_t GPR, IR::OpSize Size, uint8_t Of
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::StoreGPRRegister(uint32_t GPR, const Ref Src, IR::OpSize Size, uint8_t Offset) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
if (Size == OpSize::iInvalid) {
|
||||
Size = GPRSize;
|
||||
}
|
||||
@@ -4248,7 +4257,7 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
if (Operand.IsGPR()) {
|
||||
// 8Bit and 16bit destination types store their result without effecting the upper bits
|
||||
// 32bit ops ZEXT the result to 64bit
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
const auto gpr = Operand.Data.GPR.GPR;
|
||||
if (gpr >= FEXCore::X86State::REG_MM_0) {
|
||||
@@ -4310,7 +4319,7 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
AddressMode A = DecodeAddress(Op, Operand, AccessType, false /* IsLoad */);
|
||||
|
||||
if (OpSize == OpSize::f80Bit) {
|
||||
Ref MemStoreDst = LoadEffectiveAddress(this, A, CTX->GetGPROpSize(), true);
|
||||
Ref MemStoreDst = LoadEffectiveAddress(this, A, GetGPROpSize(), true);
|
||||
if (CTX->HostFeatures.SupportsSVE128 || CTX->HostFeatures.SupportsSVE256) {
|
||||
_StoreMemX87SVEOptPredicate(OpSize::i128Bit, OpSize::i16Bit, Src, MemStoreDst);
|
||||
} else {
|
||||
@@ -4421,7 +4430,7 @@ void OpDispatchBuilder::ALUOp(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::I
|
||||
if (Size < OpSize::i32Bit && !DestIsLockedMem(Op) && Op->Dest.IsGPR() && !Op->Dest.Data.GPR.HighBits && IsConst &&
|
||||
(ALUIROp == IR::IROps::OP_XOR || ALUIROp == IR::IROps::OP_OR || ALUIROp == IR::IROps::OP_ANDWITHFLAGS)) {
|
||||
|
||||
RoundedSize = ResultSize = CTX->GetGPROpSize();
|
||||
RoundedSize = ResultSize = GetGPROpSize();
|
||||
LOGMAN_THROW_A_FMT(Const < (1ull << IR::OpSizeAsBits(Size)), "does not clobber");
|
||||
|
||||
// For AND, we can play the same trick but we instead need the upper bits of
|
||||
@@ -4503,7 +4512,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) {
|
||||
#ifndef _WIN32
|
||||
constexpr uint8_t SYSCALL_LITERAL = 0x80;
|
||||
if (Literal == SYSCALL_LITERAL) {
|
||||
if (CTX->Config.Is64BitMode()) [[unlikely]] {
|
||||
if (Is64BitMode) [[unlikely]] {
|
||||
LogMan::Msg::EFmt("[Unsupported] Trying to execute 32-bit syscall from a 64-bit process.");
|
||||
UnhandledOp(Op);
|
||||
return;
|
||||
@@ -4576,7 +4585,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) {
|
||||
// Calculate flags early.
|
||||
FlushRegisterCache();
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
if (SetRIPToNext) {
|
||||
BlockSetRIP = SetRIPToNext;
|
||||
@@ -4635,7 +4644,7 @@ void OpDispatchBuilder::LZCNT(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::MOVBEOp(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto SrcSize = OpSizeFromSrc(Op);
|
||||
|
||||
Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = OpSize::i8Bit});
|
||||
@@ -4764,7 +4773,7 @@ void OpDispatchBuilder::RDPIDOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CRC32(OpcodeArgs) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
// Destination GPR size is always 4 or 8 bytes depending on widening
|
||||
const auto DstSize = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REX_WIDENING ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
@@ -4803,7 +4812,7 @@ void OpDispatchBuilder::RDRANDOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::BreakOp(OpcodeArgs, FEXCore::IR::BreakDefinition BreakDefinition) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
|
||||
// We don't actually support this instruction
|
||||
// Multiblock may hit it though
|
||||
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
auto it = JumpTargets.find(NextRIP);
|
||||
if (it == JumpTargets.end()) {
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
// If we don't have a jump target to a new block then we have to leave
|
||||
// Set the RIP to the next instruction and leave
|
||||
auto RelocatedNextRIP = _EntrypointOffset(GPRSize, NextRIP - Entry);
|
||||
@@ -300,7 +300,7 @@ public:
|
||||
return ShouldDump;
|
||||
}
|
||||
|
||||
void BeginFunction(uint64_t RIP, const fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks>* Blocks, uint32_t NumInstructions);
|
||||
void BeginFunction(uint64_t RIP, const fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks>* Blocks, uint32_t NumInstructions, bool Is64BitMode);
|
||||
void Finalize();
|
||||
|
||||
// Dispatch builder functions
|
||||
@@ -1197,7 +1197,7 @@ public:
|
||||
|
||||
CalculateDeferredFlags();
|
||||
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
const auto VectorSize = GetGuestVectorLength();
|
||||
|
||||
// Write backwards. This is a heuristic to improve coalescing, since we
|
||||
@@ -1270,6 +1270,10 @@ public:
|
||||
RegCache.Partial &= ~Mask;
|
||||
}
|
||||
|
||||
IR::OpSize GetGPROpSize() const {
|
||||
return Is64BitMode ? IR::OpSize::i64Bit : IR::OpSize::i32Bit;
|
||||
}
|
||||
|
||||
protected:
|
||||
void RecordX87Use() override {
|
||||
CurrentHeader->HasX87 = true;
|
||||
@@ -1971,7 +1975,7 @@ private:
|
||||
}
|
||||
|
||||
Ref LoadGPR(uint8_t Reg) {
|
||||
return LoadRegCache(Reg, GPR0Index + Reg, GPRClass, CTX->GetGPROpSize());
|
||||
return LoadRegCache(Reg, GPR0Index + Reg, GPRClass, GetGPROpSize());
|
||||
}
|
||||
|
||||
Ref LoadContext(IR::OpSize Size, uint8_t Index) {
|
||||
@@ -2371,6 +2375,7 @@ private:
|
||||
bool BlockSetRIP {false};
|
||||
|
||||
bool Multiblock {};
|
||||
bool Is64BitMode {};
|
||||
uint64_t Entry {};
|
||||
IROp_IRHeader* CurrentHeader {};
|
||||
|
||||
@@ -2405,7 +2410,7 @@ private:
|
||||
|
||||
Ref _LoadMemAutoTSO(FEXCore::IR::RegisterClassType Class, IR::OpSize Size, AddressMode A, IR::OpSize Align = IR::OpSize::i8Bit) {
|
||||
bool AtomicTSO = IsTSOEnabled(Class) && !A.NonTSO;
|
||||
A = SelectAddressMode(this, A, CTX->GetGPROpSize(), CTX->HostFeatures.SupportsTSOImm9, AtomicTSO, Class != GPRClass, Size);
|
||||
A = SelectAddressMode(this, A, GetGPROpSize(), CTX->HostFeatures.SupportsTSOImm9, AtomicTSO, Class != GPRClass, Size);
|
||||
|
||||
if (AtomicTSO) {
|
||||
return _LoadMemTSO(Class, Size, A.Base, A.Index, Align, A.IndexType, A.IndexScale);
|
||||
@@ -2425,7 +2430,7 @@ private:
|
||||
A.Offset = 0;
|
||||
}
|
||||
|
||||
Out.Base = LoadEffectiveAddress(this, A, CTX->GetGPROpSize(), true, false);
|
||||
Out.Base = LoadEffectiveAddress(this, A, GetGPROpSize(), true, false);
|
||||
return Out;
|
||||
}
|
||||
|
||||
@@ -2456,7 +2461,7 @@ private:
|
||||
|
||||
Ref _StoreMemAutoTSO(FEXCore::IR::RegisterClassType Class, IR::OpSize Size, AddressMode A, Ref Value, IR::OpSize Align = IR::OpSize::i8Bit) {
|
||||
bool AtomicTSO = IsTSOEnabled(Class) && !A.NonTSO;
|
||||
A = SelectAddressMode(this, A, CTX->GetGPROpSize(), CTX->HostFeatures.SupportsTSOImm9, AtomicTSO, Class != GPRClass, Size);
|
||||
A = SelectAddressMode(this, A, GetGPROpSize(), CTX->HostFeatures.SupportsTSOImm9, AtomicTSO, Class != GPRClass, Size);
|
||||
|
||||
if (AtomicTSO) {
|
||||
return _StoreMemTSO(Class, Size, Value, A.Base, A.Index, Align, A.IndexType, A.IndexScale);
|
||||
@@ -2507,7 +2512,7 @@ private:
|
||||
|
||||
void Push(IR::OpSize Size, Ref Value) {
|
||||
auto OldSP = LoadGPRRegister(X86State::REG_RSP);
|
||||
auto NewSP = _Push(CTX->GetGPROpSize(), Size, Value, OldSP);
|
||||
auto NewSP = _Push(GetGPROpSize(), Size, Value, OldSP);
|
||||
StoreGPRRegister(X86State::REG_RSP, NewSP);
|
||||
FlushRegisterCache();
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ void OpDispatchBuilder::AVX128_VectorXOR(OpcodeArgs) {
|
||||
void OpDispatchBuilder::AVX128_VZERO(OpcodeArgs) {
|
||||
const auto DstSize = GetDstSize(Op);
|
||||
const auto IsVZEROALL = DstSize == Core::CPUState::XMM_AVX_REG_SIZE;
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
if (IsVZEROALL) {
|
||||
// NOTE: Despite the name being VZEROALL, this will still only ever
|
||||
@@ -968,7 +968,7 @@ void OpDispatchBuilder::AVX128_VBROADCAST(OpcodeArgs) {
|
||||
}
|
||||
} else {
|
||||
// Get the address to broadcast from into a GPR.
|
||||
Ref Address = MakeSegmentAddress(Op, Op->Src[0], CTX->GetGPROpSize());
|
||||
Ref Address = MakeSegmentAddress(Op, Op->Src[0], GetGPROpSize());
|
||||
Src.Low = _VBroadcastFromMem(OpSize::i128Bit, ElementSize, Address);
|
||||
}
|
||||
|
||||
@@ -1022,7 +1022,7 @@ void OpDispatchBuilder::AVX128_InsertCVTGPR_To_FPR(OpcodeArgs) {
|
||||
|
||||
if (Op->Src[1].IsGPR()) {
|
||||
// If the source is a GPR then convert directly from the GPR.
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Op->Src[1], CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Op->Src[1], GetGPROpSize(), Op->Flags);
|
||||
Result.Low = _VSToFGPRInsert(OpSize::i128Bit, DstElementSize, SrcSize, Src1.Low, Src2, false);
|
||||
} else if (SrcSize != DstElementSize) {
|
||||
// If the source is from memory but the Source size and destination size aren't the same,
|
||||
@@ -1179,7 +1179,7 @@ void OpDispatchBuilder::AVX128_MOVBetweenGPR_FPR(OpcodeArgs) {
|
||||
RefPair Result {};
|
||||
if (Op->Src[0].IsGPR()) {
|
||||
// Loading from GPR and moving to Vector.
|
||||
Ref Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], CTX->GetGPROpSize(), Op->Flags);
|
||||
Ref Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], GetGPROpSize(), Op->Flags);
|
||||
// zext to 128bit
|
||||
Result.Low = _VCastFromGPR(OpSize::i128Bit, OpSizeFromSrc(Op), Src);
|
||||
} else {
|
||||
@@ -1227,7 +1227,7 @@ void OpDispatchBuilder::AVX128_PExtr(OpcodeArgs) {
|
||||
Index &= NumElements - 1;
|
||||
|
||||
if (Op->Dest.IsGPR()) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
// Extract already zero extends the result.
|
||||
Ref Result = _VExtractToGPR(OpSize::i128Bit, OverridenElementSize, Src.Low, Index);
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Result, GPRSize, OpSize::iInvalid);
|
||||
@@ -1341,7 +1341,7 @@ void OpDispatchBuilder::AVX128_MOVMSK(OpcodeArgs) {
|
||||
auto GPRHigh = Mask8Byte(Src.High);
|
||||
GPR = _Orlshl(OpSize::i64Bit, GPRLow, GPRHigh, 2);
|
||||
}
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, CTX->GetGPROpSize(), OpSize::iInvalid);
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, GetGPROpSize(), OpSize::iInvalid);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::AVX128_MOVMSKB(OpcodeArgs) {
|
||||
@@ -1383,7 +1383,7 @@ void OpDispatchBuilder::AVX128_PINSRImpl(OpcodeArgs, IR::OpSize ElementSize, con
|
||||
|
||||
if (Src2Op.IsGPR()) {
|
||||
// If the source is a GPR then convert directly from the GPR.
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, GetGPROpSize(), Op->Flags);
|
||||
Result.Low = _VInsGPR(OpSize::i128Bit, ElementSize, Index, Src1.Low, Src2);
|
||||
} else {
|
||||
// If loading from memory then we only load the element size
|
||||
@@ -2055,7 +2055,7 @@ void OpDispatchBuilder::AVX128_VMASKMOVImpl(OpcodeArgs, IR::OpSize ElementSize,
|
||||
auto Mask = AVX128_LoadSource_WithOpSize(Op, MaskOp, Op->Flags, !Is128Bit);
|
||||
|
||||
const auto MakeAddress = [this, Op](const X86Tables::DecodedOperand& Data) {
|
||||
return MakeSegmentAddress(Op, Data, CTX->GetGPROpSize());
|
||||
return MakeSegmentAddress(Op, Data, GetGPROpSize());
|
||||
};
|
||||
|
||||
if (IsStore) {
|
||||
@@ -2148,7 +2148,7 @@ void OpDispatchBuilder::AVX128_VectorVariableBlend(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::AVX128_SaveAVXState(Ref MemBase) {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i += 2) {
|
||||
RefPair Pair = LoadContextPair(OpSize::i128Bit, AVXHigh0Index + i);
|
||||
@@ -2157,7 +2157,7 @@ void OpDispatchBuilder::AVX128_SaveAVXState(Ref MemBase) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::AVX128_RestoreAVXState(Ref MemBase) {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i += 2) {
|
||||
auto YMMHRegs = LoadMemPair(FPRClass, OpSize::i128Bit, MemBase, i * 16 + 576);
|
||||
@@ -2168,7 +2168,7 @@ void OpDispatchBuilder::AVX128_RestoreAVXState(Ref MemBase) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::AVX128_DefaultAVXState() {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
auto ZeroRegister = LoadZeroVector(OpSize::i128Bit);
|
||||
for (uint32_t i = 0; i < NumRegs; i++) {
|
||||
|
||||
@@ -434,7 +434,7 @@ Ref OpDispatchBuilder::InsertCVTGPR_To_FPRImpl(OpcodeArgs, IR::OpSize DstSize, I
|
||||
|
||||
if (Src2Op.IsGPR()) {
|
||||
// If the source is a GPR then convert directly from the GPR.
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, GetGPROpSize(), Op->Flags);
|
||||
return _VSToFGPRInsert(DstSize, DstElementSize, SrcSize, Src1, Src2, ZeroUpperBits);
|
||||
} else if (SrcSize != DstElementSize) {
|
||||
// If the source is from memory but the Source size and destination size aren't the same,
|
||||
@@ -741,7 +741,7 @@ void OpDispatchBuilder::MOVMSKOp(OpcodeArgs, IR::OpSize ElementSize) {
|
||||
GPR = _Bfi(OpSize::i64Bit, 32, 31, GPR, GPR);
|
||||
// Shift right to only get the two sign bits we care about.
|
||||
GPR = _Lshr(OpSize::i64Bit, GPR, Constant(62));
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, CTX->GetGPROpSize(), OpSize::iInvalid);
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, GetGPROpSize(), OpSize::iInvalid);
|
||||
} else if (Size == OpSize::i128Bit && ElementSize == OpSize::i32Bit) {
|
||||
// Shift all the sign bits to the bottom of their respective elements.
|
||||
Src = _VUShrI(Size, OpSize::i32Bit, Src, 31);
|
||||
@@ -753,7 +753,7 @@ void OpDispatchBuilder::MOVMSKOp(OpcodeArgs, IR::OpSize ElementSize) {
|
||||
Src = _VAddV(Size, OpSize::i32Bit, Src);
|
||||
// Extract to a GPR.
|
||||
Ref GPR = _VExtractToGPR(Size, OpSize::i32Bit, Src, 0);
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, CTX->GetGPROpSize(), OpSize::iInvalid);
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, GPR, GetGPROpSize(), OpSize::iInvalid);
|
||||
} else {
|
||||
Ref CurrentVal = Constant(0);
|
||||
|
||||
@@ -1504,7 +1504,7 @@ void OpDispatchBuilder::VBROADCASTOp(OpcodeArgs, IR::OpSize ElementSize) {
|
||||
Result = _VDupElement(DstSize, ElementSize, Src, 0);
|
||||
} else {
|
||||
// Get the address to broadcast from into a GPR.
|
||||
Ref Address = MakeSegmentAddress(Op, Op->Src[0], CTX->GetGPROpSize());
|
||||
Ref Address = MakeSegmentAddress(Op, Op->Src[0], GetGPROpSize());
|
||||
Result = _VBroadcastFromMem(DstSize, ElementSize, Address);
|
||||
}
|
||||
|
||||
@@ -1523,7 +1523,7 @@ Ref OpDispatchBuilder::PINSROpImpl(OpcodeArgs, IR::OpSize ElementSize, const X86
|
||||
|
||||
if (Src2Op.IsGPR()) {
|
||||
// If the source is a GPR then convert directly from the GPR.
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, GetGPROpSize(), Op->Flags);
|
||||
return _VInsGPR(Size, ElementSize, Index, Src1, Src2);
|
||||
}
|
||||
|
||||
@@ -1644,7 +1644,7 @@ void OpDispatchBuilder::PExtrOp(OpcodeArgs, IR::OpSize ElementSize) {
|
||||
Index &= NumElements - 1;
|
||||
|
||||
if (Op->Dest.IsGPR()) {
|
||||
const auto GPRSize = CTX->GetGPROpSize();
|
||||
const auto GPRSize = GetGPROpSize();
|
||||
// Extract already zero extends the result.
|
||||
Ref Result = _VExtractToGPR(OpSize::i128Bit, OverridenElementSize, Src, Index);
|
||||
StoreResult_WithOpSize(GPRClass, Op, Op->Dest, Result, GPRSize, OpSize::iInvalid);
|
||||
@@ -2065,7 +2065,7 @@ Ref OpDispatchBuilder::CVTGPR_To_FPRImpl(OpcodeArgs, IR::OpSize DstElementSize,
|
||||
Ref Converted {};
|
||||
if (Src2Op.IsGPR()) {
|
||||
// If the source is a GPR then convert directly from the GPR.
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPROpSize(), Op->Flags);
|
||||
auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, GetGPROpSize(), Op->Flags);
|
||||
Converted = _Float_FromGPR_S(DstElementSize, SrcSize, Src2);
|
||||
} else if (SrcSize != DstElementSize) {
|
||||
// If the source is from memory but the Source size and destination size aren't the same,
|
||||
@@ -2355,7 +2355,7 @@ void OpDispatchBuilder::VMASKMOVOpImpl(OpcodeArgs, IR::OpSize ElementSize, IR::O
|
||||
const X86Tables::DecodedOperand& MaskOp, const X86Tables::DecodedOperand& DataOp) {
|
||||
|
||||
const auto MakeAddress = [this, Op](const X86Tables::DecodedOperand& Data) {
|
||||
return MakeSegmentAddress(Op, Data, CTX->GetGPROpSize());
|
||||
return MakeSegmentAddress(Op, Data, GetGPROpSize());
|
||||
};
|
||||
|
||||
Ref Mask = LoadSource_WithOpSize(FPRClass, Op, MaskOp, DataSize, Op->Flags);
|
||||
@@ -2398,7 +2398,7 @@ void OpDispatchBuilder::MOVBetweenGPR_FPR(OpcodeArgs, VectorOpType VectorType) {
|
||||
Ref Result {};
|
||||
if (Op->Src[0].IsGPR()) {
|
||||
// Loading from GPR and moving to Vector.
|
||||
Ref Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], CTX->GetGPROpSize(), Op->Flags);
|
||||
Ref Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], GetGPROpSize(), Op->Flags);
|
||||
// zext to 128bit
|
||||
Result = _VCastFromGPR(OpSize::i128Bit, OpSizeFromSrc(Op), Src);
|
||||
} else {
|
||||
@@ -2504,7 +2504,7 @@ Ref OpDispatchBuilder::XSaveBase(X86Tables::DecodedOp Op) {
|
||||
void OpDispatchBuilder::XSaveOpImpl(OpcodeArgs) {
|
||||
// NOTE: Mask should be EAX and EDX concatenated, but we only need to test
|
||||
// for features that are in the lower 32 bits, so EAX only is sufficient.
|
||||
const auto OpSize = CTX->GetGPROpSize();
|
||||
const auto OpSize = GetGPROpSize();
|
||||
|
||||
const auto StoreIfFlagSet = [this, OpSize](uint32_t BitIndex, auto fn, uint32_t FieldSize = 1) {
|
||||
Ref Mask = LoadGPRRegister(X86State::REG_RAX);
|
||||
@@ -2634,7 +2634,7 @@ void OpDispatchBuilder::SaveX87State(OpcodeArgs, Ref MemBase) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SaveSSEState(Ref MemBase) {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i += 2) {
|
||||
_StoreMemPair(FPRClass, OpSize::i128Bit, LoadXMMRegister(i), LoadXMMRegister(i + 1), MemBase, i * 16 + 160);
|
||||
@@ -2647,7 +2647,7 @@ void OpDispatchBuilder::SaveMXCSRState(Ref MemBase) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SaveAVXState(Ref MemBase) {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i += 2) {
|
||||
Ref Upper0 = _VDupElement(OpSize::i256Bit, OpSize::i128Bit, LoadXMMRegister(i + 0), 1);
|
||||
@@ -2676,7 +2676,7 @@ void OpDispatchBuilder::FXRStoreOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::XRstorOpImpl(OpcodeArgs) {
|
||||
const auto OpSize = CTX->GetGPROpSize();
|
||||
const auto OpSize = GetGPROpSize();
|
||||
|
||||
// If a bit in our XSTATE_BV is set, then we restore from that region of the XSAVE area,
|
||||
// otherwise, if not set, then we need to set the relevant data the bit corresponds to
|
||||
@@ -2762,7 +2762,7 @@ void OpDispatchBuilder::RestoreX87State(Ref MemBase) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::RestoreSSEState(Ref MemBase) {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i += 2) {
|
||||
auto XMMRegs = LoadMemPair(FPRClass, OpSize::i128Bit, MemBase, i * 16 + 160);
|
||||
@@ -2783,7 +2783,7 @@ void OpDispatchBuilder::RestoreMXCSRState(Ref MXCSR) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::RestoreAVXState(Ref MemBase) {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i += 2) {
|
||||
Ref XMMReg0 = LoadXMMRegister(i + 0);
|
||||
@@ -2808,7 +2808,7 @@ void OpDispatchBuilder::DefaultX87State(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::DefaultSSEState() {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
Ref ZeroVector = LoadZeroVector(OpSize::i128Bit);
|
||||
for (uint32_t i = 0; i < NumRegs; ++i) {
|
||||
@@ -2817,7 +2817,7 @@ void OpDispatchBuilder::DefaultSSEState() {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::DefaultAVXState() {
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
for (uint32_t i = 0; i < NumRegs; i++) {
|
||||
Ref Reg = LoadXMMRegister(i);
|
||||
@@ -4729,7 +4729,7 @@ void OpDispatchBuilder::VPBLENDWOp(OpcodeArgs) {
|
||||
void OpDispatchBuilder::VZEROOp(OpcodeArgs) {
|
||||
const auto DstSize = OpSizeFromDst(Op);
|
||||
const auto IsVZEROALL = DstSize == OpSize::i256Bit;
|
||||
const auto NumRegs = CTX->Config.Is64BitMode ? 16U : 8U;
|
||||
const auto NumRegs = Is64BitMode ? 16U : 8U;
|
||||
|
||||
if (IsVZEROALL) {
|
||||
// NOTE: Despite the name being VZEROALL, this will still only ever
|
||||
|
||||
@@ -125,7 +125,7 @@ void OpDispatchBuilder::FST(OpcodeArgs, IR::OpSize Width) {
|
||||
const auto SourceSize = ReducedPrecisionMode ? OpSize::i64Bit : OpSize::i128Bit;
|
||||
AddressMode A = DecodeAddress(Op, Op->Dest, MemoryAccessType::DEFAULT, false);
|
||||
|
||||
A = SelectAddressMode(this, A, CTX->GetGPROpSize(), CTX->HostFeatures.SupportsTSOImm9, false, false, Width);
|
||||
A = SelectAddressMode(this, A, GetGPROpSize(), CTX->HostFeatures.SupportsTSOImm9, false, false, Width);
|
||||
_StoreStackMem(SourceSize, Width, A.Base, A.Index, OpSize::iInvalid, A.IndexType, A.IndexScale, /*Float=*/true);
|
||||
|
||||
if (Op->TableInfo->Flags & X86Tables::InstFlags::FLAGS_POP) {
|
||||
|
||||
@@ -70,7 +70,7 @@ void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl* ctx) {
|
||||
FEX_CONFIG_OPT(DisablePasses, O0);
|
||||
|
||||
if (!DisablePasses()) {
|
||||
InsertPass(CreateX87StackOptimizationPass(ctx->HostFeatures, ctx->GetGPROpSize()));
|
||||
InsertPass(CreateX87StackOptimizationPass(ctx->HostFeatures, ctx->Config.Is64BitMode ? IR::OpSize::i64Bit : IR::OpSize::i32Bit));
|
||||
InsertPass(CreateConstProp(ctx->HostFeatures.SupportsTSOImm9));
|
||||
InsertPass(CreateDeadFlagCalculationEliminination());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user