diff --git a/External/FEXCore/Source/Interface/Core/HostFeatures.cpp b/External/FEXCore/Source/Interface/Core/HostFeatures.cpp index dba07a84f..3555e9c21 100644 --- a/External/FEXCore/Source/Interface/Core/HostFeatures.cpp +++ b/External/FEXCore/Source/Interface/Core/HostFeatures.cpp @@ -84,6 +84,16 @@ HostFeatures::HostFeatures() { SupportsCRC = Features.has(Xbyak::util::Cpu::tSSE42); SupportsRAND = Features.has(Xbyak::util::Cpu::tRDRAND) && Features.has(Xbyak::util::Cpu::tRDSEED); + // xbyak doesn't know how to check for CLZero + uint32_t eax, ebx, ecx, edx; + // First ensure we support a new enough extended CPUID function range + __cpuid(0x8000'0000, eax, ebx, ecx, edx); + if (eax >= 0x8000'0008U) { + // CLZero defined in 8000_00008_EBX[bit 0] + __cpuid(0x8000'0008, eax, ebx, ecx, edx); + SupportsCLZERO = ebx & 1; + } + SupportsFlushInputsToZero = true; SupportsFloatExceptions = true; #else diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 22059a382..e5ee8237d 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4888,6 +4888,7 @@ void OpDispatchBuilder::StoreResult(FEXCore::IR::RegisterClassType Class, FEXCor OpDispatchBuilder::OpDispatchBuilder(FEXCore::Context::Context *ctx) : CTX {ctx} { ResetWorkingList(); + InstallHostSpecificOpcodeHandlers(); } void OpDispatchBuilder::ResetWorkingList() { @@ -5233,6 +5234,91 @@ void OpDispatchBuilder::InvalidOp(OpcodeArgs) { #undef OpcodeArgs + +void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { + static bool Initialized = false; + if (!CTX || Initialized) { + // IRCompaction doesn't set a CTX and doesn't need this anyway + return; + } +#define OPD(prefix, opcode) (((prefix) << 8) | opcode) + constexpr uint16_t PF_38_66 = (1U << 0); + constexpr uint16_t PF_38_F2 = (1U << 1); + + constexpr std::tuple H0F38_AES[] = { + {OPD(PF_38_66, 0xDB), 1, &OpDispatchBuilder::AESImcOp}, + {OPD(PF_38_66, 0xDC), 1, &OpDispatchBuilder::AESEncOp}, + {OPD(PF_38_66, 0xDD), 1, &OpDispatchBuilder::AESEncLastOp}, + {OPD(PF_38_66, 0xDE), 1, &OpDispatchBuilder::AESDecOp}, + {OPD(PF_38_66, 0xDF), 1, &OpDispatchBuilder::AESDecLastOp}, + }; + constexpr std::tuple H0F38_CRC[] = { + {OPD(PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, + {OPD(PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, + + {OPD(PF_38_66 | PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, + {OPD(PF_38_66 | PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, + }; +#undef OPD + +#define OPD(REX, prefix, opcode) ((REX << 9) | (prefix << 8) | opcode) +#define PF_3A_NONE 0 +#define PF_3A_66 1 + constexpr std::tuple H0F3A_AES[] = { + {OPD(0, PF_3A_66, 0xDF), 1, &OpDispatchBuilder::AESKeyGenAssist}, + }; +#undef PF_3A_NONE +#undef PF_3A_66 +#undef OPD + +#define OPD(group, prefix, Reg) (((group - FEXCore::X86Tables::TYPE_GROUP_6) << 5) | (prefix) << 3 | (Reg)) + constexpr uint16_t PF_NONE = 0; + constexpr uint16_t PF_66 = 2; + + constexpr std::tuple SecondaryExtensionOp_RDRAND[] = { + // GROUP 9 + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 6), 1, &OpDispatchBuilder::RDRANDOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 7), 1, &OpDispatchBuilder::RDRANDOp}, + + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 6), 1, &OpDispatchBuilder::RDRANDOp}, + {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 7), 1, &OpDispatchBuilder::RDRANDOp}, + }; +#undef OPD + + constexpr std::tuple SecondaryModRMExtensionOp_CLZero[] = { + {((3 << 3) | 4), 1, &OpDispatchBuilder::CLZeroOp}, + }; + + auto InstallToTable = [](auto& FinalTable, auto& LocalTable) { + for (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) { + LOGMAN_THROW_A_FMT(FinalTable[OpNum + i].OpcodeDispatcher == nullptr, "Duplicate Entry"); + FinalTable[OpNum + i].OpcodeDispatcher = Dispatcher; + } + } + }; + + if (CTX->HostFeatures.SupportsCRC) { + InstallToTable(FEXCore::X86Tables::H0F38TableOps, H0F38_CRC); + } + + if (CTX->HostFeatures.SupportsAES) { + InstallToTable(FEXCore::X86Tables::H0F38TableOps, H0F38_AES); + InstallToTable(FEXCore::X86Tables::H0F3ATableOps, H0F3A_AES); + } + + if (CTX->HostFeatures.SupportsCLZERO) { + InstallToTable(FEXCore::X86Tables::SecondModRMTableOps, SecondaryModRMExtensionOp_CLZero); + } + + if (CTX->HostFeatures.SupportsRAND) { + InstallToTable(FEXCore::X86Tables::SecondInstGroupOps, SecondaryExtensionOp_RDRAND); + } + Initialized = true; +} + void InstallOpcodeHandlers(Context::OperatingMode Mode) { constexpr std::tuple BaseOpTable[] = { // Instructions @@ -5794,15 +5880,8 @@ constexpr uint16_t PF_F2 = 3; // GROUP 9 {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 6), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_NONE, 7), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_F3, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 6), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_66, 7), 1, &OpDispatchBuilder::RDRANDOp}, - {OPD(FEXCore::X86Tables::TYPE_GROUP_9, PF_F2, 1), 1, &OpDispatchBuilder::CMPXCHGPairOp}, // GROUP 12 @@ -5868,7 +5947,6 @@ constexpr uint16_t PF_F2 = 3; // REG /7 {((3 << 3) | 1), 1, &OpDispatchBuilder::RDTSCPOp}, - {((3 << 3) | 4), 1, &OpDispatchBuilder::CLZeroOp}, }; // Top bit indicating if it needs to be repeated with {0x40, 0x80} or'd in @@ -6110,7 +6188,6 @@ constexpr uint16_t PF_F2 = 3; #define OPD(prefix, opcode) (((prefix) << 8) | opcode) constexpr uint16_t PF_38_NONE = 0; constexpr uint16_t PF_38_66 = (1U << 0); - constexpr uint16_t PF_38_F2 = (1U << 1); constexpr uint16_t PF_38_F3 = (1U << 2); constexpr std::tuple H0F38Table[] = { @@ -6176,24 +6253,13 @@ constexpr uint16_t PF_F2 = 3; {OPD(PF_38_66, 0x40), 1, &OpDispatchBuilder::VectorALUOp}, {OPD(PF_38_66, 0x41), 1, &OpDispatchBuilder::PHMINPOSUWOp}, - {OPD(PF_38_66, 0xDB), 1, &OpDispatchBuilder::AESImcOp}, - {OPD(PF_38_66, 0xDC), 1, &OpDispatchBuilder::AESEncOp}, - {OPD(PF_38_66, 0xDD), 1, &OpDispatchBuilder::AESEncLastOp}, - {OPD(PF_38_66, 0xDE), 1, &OpDispatchBuilder::AESDecOp}, - {OPD(PF_38_66, 0xDF), 1, &OpDispatchBuilder::AESDecLastOp}, - {OPD(PF_38_NONE, 0xF0), 2, &OpDispatchBuilder::MOVBEOp}, {OPD(PF_38_66, 0xF0), 2, &OpDispatchBuilder::MOVBEOp}, - {OPD(PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, - {OPD(PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, - - {OPD(PF_38_66 | PF_38_F2, 0xF0), 1, &OpDispatchBuilder::CRC32}, - {OPD(PF_38_66 | PF_38_F2, 0xF1), 1, &OpDispatchBuilder::CRC32}, - {OPD(PF_38_66, 0xF6), 1, &OpDispatchBuilder::ADXOp}, {OPD(PF_38_F3, 0xF6), 1, &OpDispatchBuilder::ADXOp}, }; + #undef OPD #define OPD(REX, prefix, opcode) ((REX << 9) | (prefix << 8) | opcode) @@ -6225,8 +6291,6 @@ constexpr uint16_t PF_F2 = 3; {OPD(0, PF_3A_66, 0x40), 1, &OpDispatchBuilder::DPPOp<4>}, {OPD(0, PF_3A_66, 0x41), 1, &OpDispatchBuilder::DPPOp<8>}, {OPD(0, PF_3A_66, 0x42), 1, &OpDispatchBuilder::MPSADBWOp}, - - {OPD(0, PF_3A_66, 0xDF), 1, &OpDispatchBuilder::AESKeyGenAssist}, }; #undef PF_3A_NONE #undef PF_3A_66 diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 4d679e5db..1682affda 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -1175,6 +1175,8 @@ private: else return _LoadMem(Class, Size, ssa0, Invalid(), Align, MEM_OFFSET_SXTX, 1); } + + void InstallHostSpecificOpcodeHandlers(); }; void InstallOpcodeHandlers(Context::OperatingMode Mode); diff --git a/unittests/ASM/Disabled_Tests_x64 b/unittests/ASM/Disabled_Tests_x64 new file mode 100644 index 000000000..36e42b872 --- /dev/null +++ b/unittests/ASM/Disabled_Tests_x64 @@ -0,0 +1,3 @@ +# Intel doesn't support CLZero, which the CI uses +Test_SecondaryModRM/Reg_7_4.asm +Test_SecondaryModRM/Reg_7_4_2.asm