mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 16:00:18 +02:00
HostFeatures: Disable SupportsTSOImm9 for some CPUs
This change avoids using the LDAPUR instruction with CPUs that are know to be impacted by an ARM CPU errata that results in poor performance.
This commit is contained in:
1 parent
a27c4b3860
commit
8cc967fa22
3 files changed
+77
-28
No files matched your search
@@ -525,9 +525,72 @@ static void OverrideFeatures(FEXCore::HostFeatures* Features, uint64_t ForceSVEW
|
||||
Features->SupportsSVE256 = ForceSVEWidth && ForceSVEWidth >= 256;
|
||||
}
|
||||
|
||||
FEXCore::HostFeatures FetchHostFeatures(FEX::CPUFeatures& Features, bool SupportsCacheMaintenanceOps, uint64_t CTR, uint64_t MIDR) {
|
||||
FEXCore::HostFeatures HostFeatures;
|
||||
static void HandleErrata(FEXCore::HostFeatures* HostFeatures, uint64_t MIDR) {
|
||||
constexpr uint32_t Implementer_ARM = 0x41;
|
||||
constexpr uint32_t PartNum_V2 = 0xd4f;
|
||||
constexpr uint32_t PartNum_V3 = 0xd84;
|
||||
constexpr uint32_t PartNum_X3 = 0xd4e;
|
||||
constexpr uint32_t PartNum_X4 = 0xd82;
|
||||
constexpr uint32_t PartNum_X925 = 0xd85;
|
||||
|
||||
constexpr uint32_t Implementer_QCOM = 0x51;
|
||||
constexpr uint32_t PartNum_Oryon1 = 0x001;
|
||||
|
||||
auto GetMIDRImplementer = [](uint32_t MIDR) -> uint32_t {
|
||||
return (MIDR >> 24) & 0xFF;
|
||||
};
|
||||
|
||||
auto GetMIDRPartNum = [](uint32_t MIDR) -> uint32_t {
|
||||
return (MIDR >> 4) & 0xFFF;
|
||||
};
|
||||
|
||||
const uint32_t MIDR_Implementer = GetMIDRImplementer(MIDR);
|
||||
const uint32_t MIDR_PartNum = GetMIDRPartNum(MIDR);
|
||||
|
||||
#ifdef _M_ARM_64
|
||||
if (MIDR_Implementer == Implementer_QCOM && MIDR_PartNum == PartNum_Oryon1) {
|
||||
// Work around an errata in Qualcomm's Oryon.
|
||||
// While this CPU implements the RAND extension:
|
||||
// - The RNDR register works.
|
||||
// - The RNDRRS register will never read a random number. (Always return failure)
|
||||
// This is contrary to x86 RNG behaviour where it allows spurious failure with RDSEED, but guarantees eventual success.
|
||||
// This manifested itself on Linux when an x86 processor failed to guarantee forward progress and boot of services would infinite
|
||||
// loop. Just disable this extension if this CPU is detected.
|
||||
HostFeatures->SupportsRAND = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// The LDAPUR instruction suffers from significant performance issues on many ARM implementations. This is
|
||||
// listed in the official Cortex errata list as follows:
|
||||
//
|
||||
// 3877900
|
||||
// LDAPUR, LDAPURB, LDAPURH instructions have stricter memory ordering than required
|
||||
//
|
||||
// LDAPUR instructions execute with full Load-Acquire ordering instead of the relaxed ordering described
|
||||
// in the LDAPUR pseudocode. This might cause significant performance degradation in workloads that do
|
||||
// not require this stricter memory ordering. Note that this erratum only affects the unscaled versions of
|
||||
// LDAPUR (LDAPUR, LDAPURB, LDAPURH), and not LDAPR (LDAPR, LDAPRB, LDAPRH).
|
||||
//
|
||||
// The list of cores to disable its use on was taken from the following LLVM PR that accomplishes the same
|
||||
// thing: https://github.com/llvm/llvm-project/pull/124274
|
||||
for (uint32_t CoreIndex = 0; CoreIndex < HostFeatures->CPUMIDRs.size(); CoreIndex++) {
|
||||
const uint32_t CoreMIDR = HostFeatures->CPUMIDRs[CoreIndex];
|
||||
const uint32_t Core_MIDR_Implementer = GetMIDRImplementer(CoreMIDR);
|
||||
const uint32_t Core_MIDR_PartNum = GetMIDRPartNum(CoreMIDR);
|
||||
|
||||
bool IgnoreLRCPC2 = (Core_MIDR_Implementer == Implementer_ARM) &&
|
||||
((Core_MIDR_PartNum == PartNum_V2) || (Core_MIDR_PartNum == PartNum_V3) || (Core_MIDR_PartNum == PartNum_X3) ||
|
||||
(Core_MIDR_PartNum == PartNum_X4) || (Core_MIDR_PartNum == PartNum_X925));
|
||||
|
||||
if (IgnoreLRCPC2) {
|
||||
HostFeatures->SupportsTSOImm9 = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFeatures, bool SupportsCacheMaintenanceOps, uint64_t CTR,
|
||||
uint64_t MIDR) {
|
||||
FEX_CONFIG_OPT(ForceSVEWidth, FORCESVEWIDTH);
|
||||
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
|
||||
|
||||
@@ -597,23 +660,6 @@ FEXCore::HostFeatures FetchHostFeatures(FEX::CPUFeatures& Features, bool Support
|
||||
|
||||
// Set FPCR back to original just in case anything changed
|
||||
SetFPCR(OriginalFPCR);
|
||||
|
||||
if (HostFeatures.SupportsRAND) {
|
||||
constexpr uint32_t Implementer_QCOM = 0x51;
|
||||
constexpr uint32_t PartNum_Oryon1 = 0x001;
|
||||
const uint32_t MIDR_Implementer = (MIDR >> 24) & 0xFF;
|
||||
const uint32_t MIDR_PartNum = (MIDR >> 4) & 0xFFF;
|
||||
if (MIDR_Implementer == Implementer_QCOM && MIDR_PartNum == PartNum_Oryon1) {
|
||||
// Work around an errata in Qualcomm's Oryon.
|
||||
// While this CPU implements the RAND extension:
|
||||
// - The RNDR register works.
|
||||
// - The RNDRRS register will never read a random number. (Always return failure)
|
||||
// This is contrary to x86 RNG behaviour where it allows spurious failure with RDSEED, but guarantees eventual success.
|
||||
// This manifested itself on Linux when an x86 processor failed to guarantee forward progress and boot of services would infinite
|
||||
// loop. Just disable this extension if this CPU is detected.
|
||||
HostFeatures.SupportsRAND = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VIXL_SIMULATOR
|
||||
@@ -660,8 +706,8 @@ FEXCore::HostFeatures FetchHostFeatures(FEX::CPUFeatures& Features, bool Support
|
||||
#endif
|
||||
HostFeatures.SupportsPreserveAllABI = FEX_HAS_PRESERVE_ALL_ATTR;
|
||||
|
||||
HandleErrata(&HostFeatures, MIDR);
|
||||
OverrideFeatures(&HostFeatures, ForceSVEWidth());
|
||||
return HostFeatures;
|
||||
}
|
||||
|
||||
FEXCore::HostFeatures FetchHostFeatures() {
|
||||
@@ -692,8 +738,9 @@ FEXCore::HostFeatures FetchHostFeatures() {
|
||||
__asm volatile("mrs %[midr], midr_el1" : [midr] "=r"(MIDR));
|
||||
#endif
|
||||
|
||||
auto HostFeatures = FetchHostFeatures(Features, true, CTR, MIDR);
|
||||
FEXCore::HostFeatures HostFeatures = {};
|
||||
FillMIDRInformationViaLinux(&HostFeatures);
|
||||
FetchHostFeatures(Features, HostFeatures, true, CTR, MIDR);
|
||||
|
||||
HostFeatures.SupportsCPUIndexInTPIDRRO = false;
|
||||
return HostFeatures;
|
||||
|
||||
@@ -662,7 +662,8 @@ protected:
|
||||
|
||||
void FillMIDRInformationViaLinux(FEXCore::HostFeatures* Features);
|
||||
|
||||
FEXCore::HostFeatures FetchHostFeatures(FEX::CPUFeatures& Features, bool SupportsCacheMaintenanceOps, uint64_t CTR, uint64_t MIDR);
|
||||
void FetchHostFeatures(FEX::CPUFeatures& Features, FEXCore::HostFeatures& HostFeatures, bool SupportsCacheMaintenanceOps, uint64_t CTR,
|
||||
uint64_t MIDR);
|
||||
FEXCore::HostFeatures FetchHostFeatures();
|
||||
FEX::CPUFeatures GetCPUFeaturesFromIDRegisters();
|
||||
} // namespace FEX
|
||||
@@ -58,12 +58,7 @@ FEXCore::HostFeatures CPUFeatures::FetchHostFeatures(bool IsWine) {
|
||||
uint64_t CTR = ReadRegU64(Key, "CP 5801");
|
||||
uint64_t MIDR = ReadRegU64(Key, "CP 4000");
|
||||
|
||||
|
||||
auto HostFeatures = FEX::FetchHostFeatures(Features, !IsWine, CTR, MIDR);
|
||||
|
||||
// Force-disable SVE until wine/windows gain support for SVE context save/restore
|
||||
HostFeatures.SupportsSVE128 = false;
|
||||
HostFeatures.SupportsSVE256 = false;
|
||||
FEXCore::HostFeatures HostFeatures = {};
|
||||
|
||||
for (uint32_t Idx = 0; Key; Key = OpenProcessorKey(++Idx)) {
|
||||
// Truncate to 32-bits, top 32-bits are all reserved in MIDR
|
||||
@@ -71,6 +66,12 @@ FEXCore::HostFeatures CPUFeatures::FetchHostFeatures(bool IsWine) {
|
||||
RegCloseKey(Key);
|
||||
}
|
||||
|
||||
FEX::FetchHostFeatures(Features, HostFeatures, !IsWine, CTR, MIDR);
|
||||
|
||||
// Force-disable SVE until wine/windows gain support for SVE context save/restore
|
||||
HostFeatures.SupportsSVE128 = false;
|
||||
HostFeatures.SupportsSVE256 = false;
|
||||
|
||||
HostFeatures.SupportsCPUIndexInTPIDRRO = !IsWine;
|
||||
return HostFeatures;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user