diff --git a/FEXCore/Source/Interface/Core/DiskCache.cpp b/FEXCore/Source/Interface/Core/DiskCache.cpp index 1ddd90568..ed63ddb62 100644 --- a/FEXCore/Source/Interface/Core/DiskCache.cpp +++ b/FEXCore/Source/Interface/Core/DiskCache.cpp @@ -409,17 +409,18 @@ namespace DiskCache { uint64_t HostFeaturesHash; } MachineBucketData = {FormatVersion, HostFeatureHash.HostFeaturesHash}; - fextl::vector BucketBytes(sizeof(MachineBucketData) + (sizeof(uint8_t) * 2) + SerializedConfig.size()); + fextl::vector BucketBytes(sizeof(MachineBucketData) + sizeof(HostFeatureHash.ProcessFeaturesHash) + SerializedConfig.size()); memcpy(BucketBytes.data(), &MachineBucketData, sizeof(MachineBucketData)); // 64-bit mode and HostType is in the ProcessBucket hash only instead of the MachineBucketHash // These effect code-gen, but they aren't part of the MachineBucketHash, as it comes from Process state. - BucketBytes[sizeof(MachineBucketData)] = CTX->Config.Is64BitMode; - BucketBytes[sizeof(MachineBucketData) + 1] = FEXCore::ToUnderlying(HostFeatureHash.HostType); - memcpy(BucketBytes.data() + sizeof(MachineBucketData) + 2, SerializedConfig.data(), SerializedConfig.size()); + memcpy(&BucketBytes[sizeof(MachineBucketData)], &HostFeatureHash.ProcessFeaturesHash, sizeof(HostFeatureHash.ProcessFeaturesHash)); + memcpy(BucketBytes.data() + sizeof(MachineBucketData) + sizeof(HostFeatureHash.ProcessFeaturesHash), SerializedConfig.data(), + SerializedConfig.size()); uint64_t MachineBucketHash = XXH3_64bits(BucketBytes.data(), sizeof(MachineBucketData)); - uint64_t ProcessBucketHash = XXH3_64bits(BucketBytes.data() + sizeof(MachineBucketData), 2 + SerializedConfig.size()); + uint64_t ProcessBucketHash = + XXH3_64bits(BucketBytes.data() + sizeof(MachineBucketData), sizeof(HostFeatureHash.ProcessFeaturesHash) + SerializedConfig.size()); BucketHash.high64 = MachineBucketHash; BucketHash.low64 = ProcessBucketHash; diff --git a/FEXCore/Source/Interface/Core/DiskCache.h b/FEXCore/Source/Interface/Core/DiskCache.h index fb4a340ab..e39f4308e 100644 --- a/FEXCore/Source/Interface/Core/DiskCache.h +++ b/FEXCore/Source/Interface/Core/DiskCache.h @@ -249,7 +249,7 @@ namespace DiskCache { // The current version of the diskcache. // This must be changed any time codegen changes occur! // Be aware of the impact of changing this frequently! - static constexpr uint16_t FormatVersion = 34; + static constexpr uint16_t FormatVersion = 35; static constexpr uint32_t LOOKUP_KEY_MAX_BUCKET_DEPTH = 500; diff --git a/FEXCore/Source/Interface/Core/Frontend.cpp b/FEXCore/Source/Interface/Core/Frontend.cpp index 78d5f1a2e..31d647a38 100644 --- a/FEXCore/Source/Interface/Core/Frontend.cpp +++ b/FEXCore/Source/Interface/Core/Frontend.cpp @@ -1352,8 +1352,8 @@ const Decoder::DecodeStream Decoder::AdjustAddrForSpecialRegion(const uint8_t* _ constexpr uint64_t VSyscall_Base = 0xFFFF'FFFF'FF60'0000ULL; constexpr uint64_t VSyscall_End = VSyscall_Base + 0x1000; - if (BlockInfo.Is64BitMode && CTX->HostFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Linux && RIP >= VSyscall_Base && - RIP < VSyscall_End) { + if (BlockInfo.Is64BitMode && CTX->HostFeatures.ProcessFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Linux && + RIP >= VSyscall_Base && RIP < VSyscall_End) { // VSyscall // This doesn't exist on AArch64 and on x86_64 hosts this is emulated with faults to a region mapped with --xp permissions // Offset 0: vgettimeofday diff --git a/FEXCore/Source/Interface/Core/JIT/MiscOps.cpp b/FEXCore/Source/Interface/Core/JIT/MiscOps.cpp index b2dfee5bc..998f46ae7 100644 --- a/FEXCore/Source/Interface/Core/JIT/MiscOps.cpp +++ b/FEXCore/Source/Interface/Core/JIT/MiscOps.cpp @@ -76,7 +76,7 @@ DEF_OP(Break) { LoadConstant(ARMEmitter::Size::i64Bit, TMP1, Constant); str(TMP1, STATE, offsetof(FEXCore::Core::CpuStateFrame, SynchronousFaultData)); - if (CTX->HostFeatures.SupportsFaultFreeSynchronousFaults) { + if (CTX->HostFeatures.ProcessFeatures.SupportsFaultFreeSynchronousFaults) { ldr(TMP1, STATE, offsetof(FEXCore::Core::CpuStateFrame, Pointers.GuestSignal_SynchronousFault)); br(TMP1); } else { diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 0cf57cfe2..9a7494350 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4884,7 +4884,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { case 0xCD: { // INT imm8 uint8_t Literal = Op->Src[0].Literal(); - if (CTX->HostFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Linux) { + if (CTX->HostFeatures.ProcessFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Linux) { constexpr uint8_t SYSCALL_LITERAL = 0x80; if (Literal == SYSCALL_LITERAL) { if (Is64BitMode) [[unlikely]] { @@ -4896,8 +4896,8 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { SyscallOp(Op, false); return; } - } else if (CTX->HostFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Wow64 || - CTX->HostFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec) { + } else if (CTX->HostFeatures.ProcessFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Wow64 || + CTX->HostFeatures.ProcessFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec) { constexpr uint8_t SYSCALL_LITERAL = 0x2E; if (Literal == SYSCALL_LITERAL) { // Can be used for both 64-bit and 32-bit syscalls on windows @@ -4905,7 +4905,7 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) { return; } - if (CTX->HostFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec) { + if (CTX->HostFeatures.ProcessFeatures.HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec) { // This is used when QueryPerformanceCounter is called on recent Windows versions, it causes CNTVCT to be written into RAX. constexpr uint8_t GET_CNTVCT_LITERAL = 0x81; if (Literal == GET_CNTVCT_LITERAL) { @@ -5151,7 +5151,7 @@ void OpDispatchBuilder::RDTSCPOp(OpcodeArgs) { // - Explicitly use an MFENCE before this instruction if you want this behaviour // This instruction is not an execution fence, so subsequent instructions can execute after this // - Explicitly use an LFENCE after RDTSCP if you want to block this behaviour - if (CTX->HostFeatures.HostType != FEXCore::HostFeatures::HostTypeEnum::Linux && !CTX->HostFeatures.SupportsCPUIndexInTPIDRRO) { + if (CTX->HostFeatures.ProcessFeatures.HostType != FEXCore::HostFeatures::HostTypeEnum::Linux && !CTX->HostFeatures.SupportsCPUIndexInTPIDRRO) { // RDTSCP is unsupported on Win32 platforms if TPIDRRO isn't supported. UnimplementedOp(Op); return; @@ -5165,7 +5165,7 @@ void OpDispatchBuilder::RDTSCPOp(OpcodeArgs) { } void OpDispatchBuilder::RDPIDOp(OpcodeArgs) { - if (CTX->HostFeatures.HostType != FEXCore::HostFeatures::HostTypeEnum::Linux && !CTX->HostFeatures.SupportsCPUIndexInTPIDRRO) { + if (CTX->HostFeatures.ProcessFeatures.HostType != FEXCore::HostFeatures::HostTypeEnum::Linux && !CTX->HostFeatures.SupportsCPUIndexInTPIDRRO) { // RDTSCP is unsupported on Win32 platforms if TPIDRRO isn't supported. UnimplementedOp(Op); return; diff --git a/FEXCore/include/FEXCore/Core/HostFeatures.h b/FEXCore/include/FEXCore/Core/HostFeatures.h index 93584c011..80897b5a3 100644 --- a/FEXCore/include/FEXCore/Core/HostFeatures.h +++ b/FEXCore/include/FEXCore/Core/HostFeatures.h @@ -14,7 +14,7 @@ namespace FEXCore { */ struct HostFeatures { // Changes code generation slightly. - enum class HostTypeEnum : uint32_t { + enum class HostTypeEnum : uint8_t { Unknown, Linux, Wow64, @@ -32,65 +32,82 @@ struct HostFeatures { return 4 << DCacheLineLog2; } + /** + * @brief This structure contains all the data required to determine hashing at the "process" level. + * Unlike the `HostFeaturesHash` below, this data changes codegen depending on if the process is Linux, Arm64EC, or Wow64. + */ + struct ProcessFeaturesHash { + HostTypeEnum HostType : 2 {}; + uint8_t SupportsFaultFreeSynchronousFaults : 1 {}; + // This only determines the starting mode a process started in. + // The process can technically long jump to-from the other modes. + uint8_t Is64BitMode : 1 {}; + uint8_t pad : 4 {}; + }; + static_assert(sizeof(ProcessFeaturesHash) == 1); + struct CacheHash { + // This hash is used to determine the "bucket" a machine goes in to. + // This should match between Linux, Arm64EC, and Wow64. uint64_t HostFeaturesHash; - HostTypeEnum HostType; + + // This hash is used to determine features that are different between process types. + ProcessFeaturesHash ProcessFeaturesHash; }; [[nodiscard]] CacheHash HashForCaching() const { - static_assert(offsetof(HostFeatures, HostType) == 8); + static_assert(offsetof(HostFeatures, ProcessFeatures) == 8); CacheHash Result {}; memcpy(&Result.HostFeaturesHash, this, sizeof(uint64_t)); - Result.HostType = HostType; + Result.ProcessFeaturesHash = ProcessFeatures; return Result; } // Affects codegen and is basically machine description. - uint32_t DCacheLineLog2 : 4 {}; - uint32_t SupportsCacheMaintenanceOps : 1 {}; - uint32_t SupportsAES : 1 {}; - uint32_t SupportsCRC : 1 {}; - uint32_t SupportsCLZERO : 1 {}; - uint32_t SupportsAtomics : 1 {}; - uint32_t SupportsRCPC : 1 {}; - uint32_t SupportsTSOImm9 : 1 {}; - uint32_t SupportsRAND : 1 {}; - uint32_t SupportsAVX : 1 {}; - uint32_t SupportsSVE128 : 1 {}; - uint32_t SupportsSVE256 : 1 {}; - uint32_t SupportsSHA : 1 {}; - uint32_t SupportsPMULL_128Bit : 1 {}; - uint32_t SupportsCSSC : 1 {}; - uint32_t SupportsFCMA : 1 {}; - uint32_t SupportsFlagM : 1 {}; - uint32_t SupportsFlagM2 : 1 {}; - uint32_t SupportsRPRES : 1 {}; - uint32_t SupportsPreserveAllABI : 1 {}; - uint32_t SupportsAES256 : 1 {}; - uint32_t SupportsSVEBitPerm : 1 {}; - uint32_t SupportsCPUIndexInTPIDRRO : 1 {}; - uint32_t SupportsFRINTTS : 1 {}; - uint32_t SupportsECV : 1 {}; - uint32_t SupportsWFXT : 1 {}; - uint32_t Supports3DNow : 1 {}; - uint32_t SupportsSSE4a : 1 {}; - uint32_t SupportsMOPS : 1 {}; - uint32_t SupportsI8MM : 1 {}; - uint32_t SupportsDotProd : 1 {}; - uint32_t PreferZVAForVZero : 1 {}; - uint32_t SupportsAFP : 1 {}; - uint32_t SupportsFloatExceptions : 1 {}; - uint32_t SupportsFaultFreeSynchronousFaults : 1 {}; - uint32_t SupportsBF16 : 1 {}; + uint32_t DCacheLineLog2 : 4 {}; + uint32_t SupportsCacheMaintenanceOps : 1 {}; + uint32_t SupportsAES : 1 {}; + uint32_t SupportsCRC : 1 {}; + uint32_t SupportsCLZERO : 1 {}; + uint32_t SupportsAtomics : 1 {}; + uint32_t SupportsRCPC : 1 {}; + uint32_t SupportsTSOImm9 : 1 {}; + uint32_t SupportsRAND : 1 {}; + uint32_t SupportsAVX : 1 {}; + uint32_t SupportsSVE128 : 1 {}; + uint32_t SupportsSVE256 : 1 {}; + uint32_t SupportsSHA : 1 {}; + uint32_t SupportsPMULL_128Bit : 1 {}; + uint32_t SupportsCSSC : 1 {}; + uint32_t SupportsFCMA : 1 {}; + uint32_t SupportsFlagM : 1 {}; + uint32_t SupportsFlagM2 : 1 {}; + uint32_t SupportsRPRES : 1 {}; + uint32_t SupportsPreserveAllABI : 1 {}; + uint32_t SupportsAES256 : 1 {}; + uint32_t SupportsSVEBitPerm : 1 {}; + uint32_t SupportsCPUIndexInTPIDRRO : 1 {}; + uint32_t SupportsFRINTTS : 1 {}; + uint32_t SupportsECV : 1 {}; + uint32_t SupportsWFXT : 1 {}; + uint32_t Supports3DNow : 1 {}; + uint32_t SupportsSSE4a : 1 {}; + uint32_t SupportsMOPS : 1 {}; + uint32_t SupportsI8MM : 1 {}; + uint32_t SupportsDotProd : 1 {}; + uint32_t PreferZVAForVZero : 1 {}; + uint32_t SupportsAFP : 1 {}; + uint32_t SupportsFloatExceptions : 1 {}; + uint32_t SupportsBF16 : 1 {}; // Flag if this is InstCountCI uint32_t IsInstCountCI : 1 {}; - uint32_t pad : 24 {}; + uint32_t pad : 25 {}; // This affects codegen, but it isn't machine state - HostTypeEnum HostType {}; + ProcessFeaturesHash ProcessFeatures {}; // MIDR information // Also used for determining number of CPU cores for CPUID diff --git a/Source/Common/HostFeatures.cpp b/Source/Common/HostFeatures.cpp index 429725006..97a0cbcee 100644 --- a/Source/Common/HostFeatures.cpp +++ b/Source/Common/HostFeatures.cpp @@ -601,7 +601,7 @@ void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFe OverrideFeatures(&HostFeatures, ForceSVEWidth()); } -FEXCore::HostFeatures FetchHostFeatures() { +FEXCore::HostFeatures FetchHostFeatures(bool Is64BitMode) { FEX_CONFIG_OPT(CPUFeatureRegisters, CPUFEATUREREGISTERS); CPUFeatures Features {}; @@ -634,7 +634,10 @@ FEXCore::HostFeatures FetchHostFeatures() { FetchHostFeatures(Features, HostFeatures, true, CTR, MIDR); HostFeatures.SupportsCPUIndexInTPIDRRO = false; - HostFeatures.HostType = FEXCore::HostFeatures::HostTypeEnum::Linux; + HostFeatures.ProcessFeatures.HostType = FEXCore::HostFeatures::HostTypeEnum::Linux; + HostFeatures.ProcessFeatures.Is64BitMode = Is64BitMode; + // Fault free syncronous faults unsupported on Linux for now. + HostFeatures.ProcessFeatures.SupportsFaultFreeSynchronousFaults = false; HostFeatures.ProcessPID = ::getpid(); return HostFeatures; } diff --git a/Source/Common/HostFeatures.h b/Source/Common/HostFeatures.h index 0fe73c9c5..667d67896 100644 --- a/Source/Common/HostFeatures.h +++ b/Source/Common/HostFeatures.h @@ -692,6 +692,6 @@ void FillMIDRInformationViaLinux(FEXCore::HostFeatures* Features); void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFeatures, bool SupportsCacheMaintenanceOps, uint64_t CTR, uint64_t MIDR); -FEXCore::HostFeatures FetchHostFeatures(); +FEXCore::HostFeatures FetchHostFeatures(bool Is64BitMode); FEX::CPUFeatures GetCPUFeaturesFromIDRegisters(); } // namespace FEX diff --git a/Source/Tools/CodeSizeValidation/Main.cpp b/Source/Tools/CodeSizeValidation/Main.cpp index 94e4c75cd..c3ed88f4e 100644 --- a/Source/Tools/CodeSizeValidation/Main.cpp +++ b/Source/Tools/CodeSizeValidation/Main.cpp @@ -702,7 +702,7 @@ int main(int argc, char** argv, char** const envp) { // Create FEXCore context. fextl::unique_ptr CTX; { - auto HostFeatures = FEX::FetchHostFeatures(); + auto HostFeatures = FEX::FetchHostFeatures(TestHeaderData->Bitness == 64); HostFeatures.IsInstCountCI = true; CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures); } diff --git a/Source/Tools/FEXInterpreter/FEXInterpreter.cpp b/Source/Tools/FEXInterpreter/FEXInterpreter.cpp index 52bdba1e6..2881ad9ce 100644 --- a/Source/Tools/FEXInterpreter/FEXInterpreter.cpp +++ b/Source/Tools/FEXInterpreter/FEXInterpreter.cpp @@ -550,7 +550,7 @@ int main(int argc, char** argv, char** const envp) { bool SupportsSVE256 {}; fextl::unique_ptr CTX; { - auto HostFeatures = FEX::FetchHostFeatures(); + auto HostFeatures = FEX::FetchHostFeatures(Loader.Is64BitMode()); CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures); SupportsAVX = HostFeatures.SupportsAVX; SupportsSVE256 = HostFeatures.SupportsSVE256; diff --git a/Source/Tools/FEXOfflineCompiler/Main.cpp b/Source/Tools/FEXOfflineCompiler/Main.cpp index 484aeb8c7..866d5d12e 100644 --- a/Source/Tools/FEXOfflineCompiler/Main.cpp +++ b/Source/Tools/FEXOfflineCompiler/Main.cpp @@ -410,7 +410,7 @@ static std::optional GenerateSingleCache(FEXCore::ExecutableFileInf // Load HostFeatures #ifndef _WIN32 - auto HostFeatures = FEX::FetchHostFeatures(); + auto HostFeatures = FEX::FetchHostFeatures(Is64Bit); #else const auto NtDll = GetModuleHandleW(L"ntdll.dll"); const bool IsWine = !!GetProcAddress(NtDll, "wine_get_version"); diff --git a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp index 420a03333..87e5d2d24 100644 --- a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp +++ b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp @@ -245,7 +245,7 @@ int main(int argc, char** argv, char** const envp) { bool SupportsAVX = false; FEXCore::Core::CPUState State; - auto HostFeatures = FEX::FetchHostFeatures(); + auto HostFeatures = FEX::FetchHostFeatures(Loader.Is64BitMode()); auto CTX = FEXCore::Context::Context::CreateNewContext(HostFeatures); #ifndef _WIN32 diff --git a/Source/Windows/Common/CPUFeatures.cpp b/Source/Windows/Common/CPUFeatures.cpp index 4da5c0803..bc4dfb08c 100644 --- a/Source/Windows/Common/CPUFeatures.cpp +++ b/Source/Windows/Common/CPUFeatures.cpp @@ -83,16 +83,15 @@ FEXCore::HostFeatures CPUFeatures::FetchHostFeatures(bool IsWine, FEXCore::HostF HostFeatures.SupportsCPUIndexInTPIDRRO = !IsWine; - HostFeatures.HostType = HostType; HostFeatures.ProcessPID = ProcessPID; - if (HostType == FEXCore::HostFeatures::HostTypeEnum::Wow64) { - // AVX is unsupported for WOW64 - HostFeatures.SupportsAVX = false; - } else { - // arm64ec supports synchronous faults without a double-fault dance. - HostFeatures.SupportsFaultFreeSynchronousFaults = true; - } + // AVX is unsupported for WOW64 + HostFeatures.SupportsAVX = HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec; + + HostFeatures.ProcessFeatures.HostType = HostType; + HostFeatures.ProcessFeatures.Is64BitMode = HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec; + // arm64ec supports synchronous faults without a double-fault dance. + HostFeatures.ProcessFeatures.SupportsFaultFreeSynchronousFaults = HostType == FEXCore::HostFeatures::HostTypeEnum::Arm64ec; return HostFeatures; }