diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index e986a93576..7ac577afcd 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -319,6 +319,8 @@ void OpDispatchBuilder::ADCOp(OpcodeArgs) { } } +template void OpDispatchBuilder::ADCOp<0>(OpcodeArgs); + template void OpDispatchBuilder::SBBOp(OpcodeArgs) { // Calculate flags early. @@ -347,6 +349,8 @@ void OpDispatchBuilder::SBBOp(OpcodeArgs) { } } +template void OpDispatchBuilder::SBBOp<0>(OpcodeArgs); + void OpDispatchBuilder::SALCOp(OpcodeArgs) { CalculateDeferredFlags(); @@ -480,6 +484,13 @@ void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs) { Push(DstSize, Src); } +template void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::PUSHSegmentOp(OpcodeArgs); + void OpDispatchBuilder::POPOp(OpcodeArgs) { Ref Value = Pop(GetSrcSize(Op)); StoreResult(GPRClass, Op, Value, -1); @@ -539,6 +550,12 @@ void OpDispatchBuilder::POPSegmentOp(OpcodeArgs) { UpdatePrefixFromSegment(NewSegment, SegmentReg); } +template void OpDispatchBuilder::POPSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::POPSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::POPSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::POPSegmentOp(OpcodeArgs); +template void OpDispatchBuilder::POPSegmentOp(OpcodeArgs); + void OpDispatchBuilder::LEAVEOp(OpcodeArgs) { // First we move RBP in to RSP and then behave effectively like a pop auto SP = _RMWHandle(LoadGPRRegister(X86State::REG_RBP)); @@ -1039,6 +1056,8 @@ void OpDispatchBuilder::TESTOp(OpcodeArgs) { InvalidateAF(); } +template void OpDispatchBuilder::TESTOp<0>(OpcodeArgs); + void OpDispatchBuilder::MOVSXDOp(OpcodeArgs) { // This instruction is a bit special // if SrcSize == 2 @@ -1093,6 +1112,8 @@ void OpDispatchBuilder::CMPOp(OpcodeArgs) { CalculateFlags_SUB(GetSrcSize(Op), Dest, Src); } +template void OpDispatchBuilder::CMPOp<0>(OpcodeArgs); + void OpDispatchBuilder::CQOOp(OpcodeArgs) { Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags); auto Size = GetSrcSize(Op); @@ -1319,6 +1340,9 @@ void OpDispatchBuilder::MOVSegOp(OpcodeArgs) { } } +template void OpDispatchBuilder::MOVSegOp(OpcodeArgs); +template void OpDispatchBuilder::MOVSegOp(OpcodeArgs); + void OpDispatchBuilder::MOVOffsetOp(OpcodeArgs) { Ref Src; @@ -4549,6 +4573,8 @@ void OpDispatchBuilder::MOVGPROp(OpcodeArgs) { StoreResult(GPRClass, Op, Src, 1); } +template void OpDispatchBuilder::MOVGPROp<0>(OpcodeArgs); + void OpDispatchBuilder::MOVGPRNTOp(OpcodeArgs) { Ref Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.Align = 1}); StoreResult(GPRClass, Op, Src, 1, MemoryAccessType::STREAM); @@ -5501,107 +5527,6 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { } void InstallOpcodeHandlers(Context::OperatingMode Mode) { - constexpr std::tuple BaseOpTable[] = { - // Instructions - {0x00, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_ADD, FEXCore::IR::IROps::OP_ATOMICFETCHADD, 0>}, - - {0x08, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_OR, FEXCore::IR::IROps::OP_ATOMICFETCHOR, 0>}, - - {0x10, 6, &OpDispatchBuilder::ADCOp<0>}, - - {0x18, 6, &OpDispatchBuilder::SBBOp<0>}, - - {0x20, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_ANDWITHFLAGS, FEXCore::IR::IROps::OP_ATOMICFETCHAND, 0>}, - - {0x28, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_SUB, FEXCore::IR::IROps::OP_ATOMICFETCHSUB, 0>}, - - {0x30, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_XOR, FEXCore::IR::IROps::OP_ATOMICFETCHXOR, 0>}, - - {0x38, 6, &OpDispatchBuilder::CMPOp<0>}, - {0x50, 8, &OpDispatchBuilder::PUSHREGOp}, - {0x58, 8, &OpDispatchBuilder::POPOp}, - {0x68, 1, &OpDispatchBuilder::PUSHOp}, - {0x69, 1, &OpDispatchBuilder::IMUL2SrcOp}, - {0x6A, 1, &OpDispatchBuilder::PUSHOp}, - {0x6B, 1, &OpDispatchBuilder::IMUL2SrcOp}, - {0x6C, 4, &OpDispatchBuilder::PermissionRestrictedOp}, - - {0x70, 16, &OpDispatchBuilder::CondJUMPOp}, - {0x84, 2, &OpDispatchBuilder::TESTOp<0>}, - {0x86, 2, &OpDispatchBuilder::XCHGOp}, - {0x88, 4, &OpDispatchBuilder::MOVGPROp<0>}, - - {0x8C, 1, &OpDispatchBuilder::MOVSegOp}, - {0x8D, 1, &OpDispatchBuilder::LEAOp}, - {0x8E, 1, &OpDispatchBuilder::MOVSegOp}, - {0x8F, 1, &OpDispatchBuilder::POPOp}, - {0x90, 8, &OpDispatchBuilder::XCHGOp}, - - {0x98, 1, &OpDispatchBuilder::CDQOp}, - {0x99, 1, &OpDispatchBuilder::CQOOp}, - {0x9B, 1, &OpDispatchBuilder::NOPOp}, - {0x9C, 1, &OpDispatchBuilder::PUSHFOp}, - {0x9D, 1, &OpDispatchBuilder::POPFOp}, - {0x9E, 1, &OpDispatchBuilder::SAHFOp}, - {0x9F, 1, &OpDispatchBuilder::LAHFOp}, - {0xA0, 4, &OpDispatchBuilder::MOVOffsetOp}, - {0xA4, 2, &OpDispatchBuilder::MOVSOp}, - - {0xA6, 2, &OpDispatchBuilder::CMPSOp}, - {0xA8, 2, &OpDispatchBuilder::TESTOp<0>}, - {0xAA, 2, &OpDispatchBuilder::STOSOp}, - {0xAC, 2, &OpDispatchBuilder::LODSOp}, - {0xAE, 2, &OpDispatchBuilder::SCASOp}, - {0xB0, 16, &OpDispatchBuilder::MOVGPROp<0>}, - {0xC2, 2, &OpDispatchBuilder::RETOp}, - {0xC8, 1, &OpDispatchBuilder::EnterOp}, - {0xC9, 1, &OpDispatchBuilder::LEAVEOp}, - {0xCC, 2, &OpDispatchBuilder::INTOp}, - {0xCF, 1, &OpDispatchBuilder::IRETOp}, - {0xD7, 2, &OpDispatchBuilder::XLATOp}, - {0xE0, 3, &OpDispatchBuilder::LoopOp}, - {0xE3, 1, &OpDispatchBuilder::CondJUMPRCXOp}, - {0xE4, 4, &OpDispatchBuilder::PermissionRestrictedOp}, - {0xE8, 1, &OpDispatchBuilder::CALLOp}, - {0xE9, 1, &OpDispatchBuilder::JUMPOp}, - {0xEB, 1, &OpDispatchBuilder::JUMPOp}, - {0xEC, 4, &OpDispatchBuilder::PermissionRestrictedOp}, - {0xF1, 1, &OpDispatchBuilder::INTOp}, - {0xF4, 1, &OpDispatchBuilder::INTOp}, - - {0xF5, 1, &OpDispatchBuilder::FLAGControlOp}, - {0xF8, 2, &OpDispatchBuilder::FLAGControlOp}, - {0xFA, 2, &OpDispatchBuilder::PermissionRestrictedOp}, - {0xFC, 2, &OpDispatchBuilder::FLAGControlOp}, - }; - - constexpr std::tuple BaseOpTable_32[] = { - {0x06, 1, &OpDispatchBuilder::PUSHSegmentOp}, - {0x07, 1, &OpDispatchBuilder::POPSegmentOp}, - {0x0E, 1, &OpDispatchBuilder::PUSHSegmentOp}, - {0x16, 1, &OpDispatchBuilder::PUSHSegmentOp}, - {0x17, 1, &OpDispatchBuilder::POPSegmentOp}, - {0x1E, 1, &OpDispatchBuilder::PUSHSegmentOp}, - {0x1F, 1, &OpDispatchBuilder::POPSegmentOp}, - {0x27, 1, &OpDispatchBuilder::DAAOp}, - {0x2F, 1, &OpDispatchBuilder::DASOp}, - {0x37, 1, &OpDispatchBuilder::AAAOp}, - {0x3F, 1, &OpDispatchBuilder::AASOp}, - {0x40, 8, &OpDispatchBuilder::INCOp}, - {0x48, 8, &OpDispatchBuilder::DECOp}, - - {0x60, 1, &OpDispatchBuilder::PUSHAOp}, - {0x61, 1, &OpDispatchBuilder::POPAOp}, - {0xCE, 1, &OpDispatchBuilder::INTOp}, - {0xD4, 1, &OpDispatchBuilder::AAMOp}, - {0xD5, 1, &OpDispatchBuilder::AADOp}, - {0xD6, 1, &OpDispatchBuilder::SALCOp}, - }; - - constexpr std::tuple BaseOpTable_64[] = { - {0x63, 1, &OpDispatchBuilder::MOVSXDOp}, - }; - constexpr std::tuple TwoByteOpTable[] = { // Instructions {0x06, 1, &OpDispatchBuilder::PermissionRestrictedOp}, @@ -6894,12 +6819,9 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { } }; - InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable); if (Mode == Context::MODE_32BIT) { - InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable_32); InstallToTable(FEXCore::X86Tables::SecondBaseOps, TwoByteOpTable_32); } else { - InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable_64); InstallToTable(FEXCore::X86Tables::SecondBaseOps, TwoByteOpTable_64); } diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 09220ac6bf..188035d745 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -2508,6 +2508,23 @@ class OpDispatchBuilder final : public IREmitter { void CheckLegacySegmentRead(Ref NewNode, uint32_t SegmentReg); }; +constexpr inline void InstallToTable(auto& FinalTable, const auto& LocalTable) { + for (const auto& Op : LocalTable) { + auto OpNum = std::get<0>(Op); + auto Dispatcher = std::get<2>(Op); + for (uint8_t i = 0; i < std::get<1>(Op); ++i) { + auto& TableOp = FinalTable[OpNum + i]; +#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED + if (TableOp.OpcodeDispatcher) { + ERROR_AND_DIE_FMT("Duplicate Entry {}", TableOp.Name); + } +#endif + + TableOp.OpcodeDispatcher = Dispatcher; + } + } +} + void InstallOpcodeHandlers(Context::OperatingMode Mode); } // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h new file mode 100644 index 0000000000..c9a1edcdab --- /dev/null +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/BaseTables.h @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +#pragma once +#include "Interface/Core/OpcodeDispatcher.h" + +namespace FEXCore::IR { +constexpr inline std::tuple OpDispatch_BaseOpTable[] = { + // Instructions + {0x00, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_ADD, FEXCore::IR::IROps::OP_ATOMICFETCHADD, 0>}, + + {0x08, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_OR, FEXCore::IR::IROps::OP_ATOMICFETCHOR, 0>}, + + {0x10, 6, &OpDispatchBuilder::ADCOp<0>}, + + {0x18, 6, &OpDispatchBuilder::SBBOp<0>}, + + {0x20, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_ANDWITHFLAGS, FEXCore::IR::IROps::OP_ATOMICFETCHAND, 0>}, + + {0x28, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_SUB, FEXCore::IR::IROps::OP_ATOMICFETCHSUB, 0>}, + + {0x30, 6, &OpDispatchBuilder::Bind<&OpDispatchBuilder::ALUOp, FEXCore::IR::IROps::OP_XOR, FEXCore::IR::IROps::OP_ATOMICFETCHXOR, 0>}, + + {0x38, 6, &OpDispatchBuilder::CMPOp<0>}, + {0x50, 8, &OpDispatchBuilder::PUSHREGOp}, + {0x58, 8, &OpDispatchBuilder::POPOp}, + {0x68, 1, &OpDispatchBuilder::PUSHOp}, + {0x69, 1, &OpDispatchBuilder::IMUL2SrcOp}, + {0x6A, 1, &OpDispatchBuilder::PUSHOp}, + {0x6B, 1, &OpDispatchBuilder::IMUL2SrcOp}, + {0x6C, 4, &OpDispatchBuilder::PermissionRestrictedOp}, + + {0x70, 16, &OpDispatchBuilder::CondJUMPOp}, + {0x84, 2, &OpDispatchBuilder::TESTOp<0>}, + {0x86, 2, &OpDispatchBuilder::XCHGOp}, + {0x88, 4, &OpDispatchBuilder::MOVGPROp<0>}, + + {0x8C, 1, &OpDispatchBuilder::MOVSegOp}, + {0x8D, 1, &OpDispatchBuilder::LEAOp}, + {0x8E, 1, &OpDispatchBuilder::MOVSegOp}, + {0x8F, 1, &OpDispatchBuilder::POPOp}, + {0x90, 8, &OpDispatchBuilder::XCHGOp}, + + {0x98, 1, &OpDispatchBuilder::CDQOp}, + {0x99, 1, &OpDispatchBuilder::CQOOp}, + {0x9B, 1, &OpDispatchBuilder::NOPOp}, + {0x9C, 1, &OpDispatchBuilder::PUSHFOp}, + {0x9D, 1, &OpDispatchBuilder::POPFOp}, + {0x9E, 1, &OpDispatchBuilder::SAHFOp}, + {0x9F, 1, &OpDispatchBuilder::LAHFOp}, + {0xA4, 2, &OpDispatchBuilder::MOVSOp}, + + {0xA6, 2, &OpDispatchBuilder::CMPSOp}, + {0xA8, 2, &OpDispatchBuilder::TESTOp<0>}, + {0xAA, 2, &OpDispatchBuilder::STOSOp}, + {0xAC, 2, &OpDispatchBuilder::LODSOp}, + {0xAE, 2, &OpDispatchBuilder::SCASOp}, + {0xB0, 16, &OpDispatchBuilder::MOVGPROp<0>}, + {0xC2, 2, &OpDispatchBuilder::RETOp}, + {0xC8, 1, &OpDispatchBuilder::EnterOp}, + {0xC9, 1, &OpDispatchBuilder::LEAVEOp}, + {0xCC, 2, &OpDispatchBuilder::INTOp}, + {0xCF, 1, &OpDispatchBuilder::IRETOp}, + {0xD7, 2, &OpDispatchBuilder::XLATOp}, + {0xE0, 3, &OpDispatchBuilder::LoopOp}, + {0xE3, 1, &OpDispatchBuilder::CondJUMPRCXOp}, + {0xE4, 4, &OpDispatchBuilder::PermissionRestrictedOp}, + {0xE8, 1, &OpDispatchBuilder::CALLOp}, + {0xE9, 1, &OpDispatchBuilder::JUMPOp}, + {0xEB, 1, &OpDispatchBuilder::JUMPOp}, + {0xEC, 4, &OpDispatchBuilder::PermissionRestrictedOp}, + {0xF1, 1, &OpDispatchBuilder::INTOp}, + {0xF4, 1, &OpDispatchBuilder::INTOp}, + + {0xF5, 1, &OpDispatchBuilder::FLAGControlOp}, + {0xF8, 2, &OpDispatchBuilder::FLAGControlOp}, + {0xFA, 2, &OpDispatchBuilder::PermissionRestrictedOp}, + {0xFC, 2, &OpDispatchBuilder::FLAGControlOp}, +}; + +constexpr inline std::tuple OpDispatch_BaseOpTable_64[] = { + {0x63, 1, &OpDispatchBuilder::MOVSXDOp}, + {0xA0, 4, &OpDispatchBuilder::MOVOffsetOp}, +}; + +constexpr inline std::tuple OpDispatch_BaseOpTable_32[] = { + {0x06, 1, &OpDispatchBuilder::PUSHSegmentOp}, + {0x07, 1, &OpDispatchBuilder::POPSegmentOp}, + {0x0E, 1, &OpDispatchBuilder::PUSHSegmentOp}, + {0x16, 1, &OpDispatchBuilder::PUSHSegmentOp}, + {0x17, 1, &OpDispatchBuilder::POPSegmentOp}, + {0x1E, 1, &OpDispatchBuilder::PUSHSegmentOp}, + {0x1F, 1, &OpDispatchBuilder::POPSegmentOp}, + {0x27, 1, &OpDispatchBuilder::DAAOp}, + {0x2F, 1, &OpDispatchBuilder::DASOp}, + {0x37, 1, &OpDispatchBuilder::AAAOp}, + {0x3F, 1, &OpDispatchBuilder::AASOp}, + {0x40, 8, &OpDispatchBuilder::INCOp}, + {0x48, 8, &OpDispatchBuilder::DECOp}, + + {0x60, 1, &OpDispatchBuilder::PUSHAOp}, + {0x61, 1, &OpDispatchBuilder::POPAOp}, + {0xA0, 4, &OpDispatchBuilder::MOVOffsetOp}, + {0xCE, 1, &OpDispatchBuilder::INTOp}, + {0xD4, 1, &OpDispatchBuilder::AAMOp}, + {0xD5, 1, &OpDispatchBuilder::AADOp}, + {0xD6, 1, &OpDispatchBuilder::SALCOp}, +}; +} // namespace FEXCore::IR diff --git a/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp b/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp index 69ed215c49..7ede755bd9 100644 --- a/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp +++ b/FEXCore/Source/Interface/Core/X86Tables/BaseTables.cpp @@ -6,6 +6,7 @@ tags: frontend|x86-tables */ #include "Interface/Core/X86Tables/X86Tables.h" +#include "Interface/Core/OpcodeDispatcher/BaseTables.h" #include @@ -236,6 +237,7 @@ std::array BaseOps = []() consteval { }; GenerateTable(&Table.at(0), BaseOpTable, std::size(BaseOpTable)); + IR::InstallToTable(Table, IR::OpDispatch_BaseOpTable); return Table; }(); @@ -301,9 +303,11 @@ void InitializeBaseTables(Context::OperatingMode Mode) { if (Mode == Context::MODE_64BIT) { GenerateTable(&BaseOps.at(0), BaseOpTable_64, std::size(BaseOpTable_64)); + IR::InstallToTable(BaseOps, IR::OpDispatch_BaseOpTable_64); } else { GenerateTable(&BaseOps.at(0), BaseOpTable_32, std::size(BaseOpTable_32)); + IR::InstallToTable(BaseOps, IR::OpDispatch_BaseOpTable_32); } } } diff --git a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h index 2dba6d75b2..0ab423e1c0 100644 --- a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h +++ b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h @@ -518,7 +518,10 @@ constexpr static inline void GenerateTable(X86InstInfo *FinalTable, X86TablesInf X86InstInfo const &Info = Op.Info; for (uint32_t i = 0; i < Op.second; ++i) { if (FinalTable[OpNum + i].Type != TYPE_UNKNOWN) { - ERROR_AND_DIE_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name); + LOGMAN_MSG_A_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name); + } + if (FinalTable[OpNum + i].OpcodeDispatcher) { + LOGMAN_MSG_A_FMT("Already installed an OpcodeDispatcher for 0x{:x}", OpNum + i); } FinalTable[OpNum + i] = Info; } @@ -533,7 +536,7 @@ constexpr static inline void GenerateTableWithCopy(X86InstInfo *FinalTable, X86T X86InstInfo const &Info = Op.Info; for (uint32_t i = 0; i < Op.second; ++i) { if (FinalTable[OpNum + i].Type != TYPE_UNKNOWN) { - ERROR_AND_DIE_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name); + LOGMAN_MSG_A_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name); } if (Info.Type == TYPE_COPY_OTHER) { FinalTable[OpNum + i] = OtherLocal[OpNum + i]; @@ -568,7 +571,7 @@ constexpr static inline void GenerateX87Table(X86InstInfo *FinalTable, X86Tables X86InstInfo const &Info = Op.Info; for (uint32_t i = 0; i < Op.second; ++i) { if (FinalTable[OpNum + i].Type != TYPE_UNKNOWN) { - ERROR_AND_DIE_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name); + LOGMAN_MSG_A_FMT("Duplicate Entry {}->{}", FinalTable[OpNum + i].Name, Info.Name); } if ((OpNum & 0b11'000'000) == 0b11'000'000) { // If the mod field is 0b11 then it is a regular op