diff --git a/Utilities/JIT.h b/Utilities/JIT.h index 42b3afa922..cbba82b960 100644 --- a/Utilities/JIT.h +++ b/Utilities/JIT.h @@ -495,6 +495,7 @@ namespace llvm class LLVMContext; class ExecutionEngine; class Module; + class StringRef; } // Temporary compiler interface @@ -560,4 +561,6 @@ public: bool add_sub_disk_space(ssz space); }; +llvm::StringRef fallback_cpu_detection(); + #endif // LLVM_AVAILABLE diff --git a/Utilities/JITLLVM.cpp b/Utilities/JITLLVM.cpp index 09f3ca4b85..616979f474 100644 --- a/Utilities/JITLLVM.cpp +++ b/Utilities/JITLLVM.cpp @@ -440,6 +440,12 @@ std::string jit_compiler::cpu(const std::string& _cpu) { m_cpu = llvm::sys::getHostCPUName().str(); + if (m_cpu == "generic") + { + // Try to detect a best match based on other criteria + m_cpu = fallback_cpu_detection(); + } + if (m_cpu == "sandybridge" || m_cpu == "ivybridge" || m_cpu == "haswell" || @@ -717,4 +723,49 @@ u64 jit_compiler::get(const std::string& name) return m_engine->getGlobalValueAddress(name); } +llvm::StringRef fallback_cpu_detection() +{ +#if defined (ARCH_X64) + // If we got here we either have a very old and outdated CPU or a new CPU that has not been seen by LLVM yet. + llvm::StringRef brand = utils::get_cpu_brand(); + const auto family = utils::get_cpu_family(); + const auto model = utils::get_cpu_model(); + + if (brand.startswith("AMD")) + { + switch (family) + { + case 0x17: + case 0x18: + // No major differences between znver1 and znver2, return the lesser + return "znver1"; + case 0x19: + // Models 0-Fh are zen3 as are 20h-60h. The rest we can assume are zen4 + return ((model >= 0x20 && model <= 0x60) || model < 0x10) + ? "znver3" + : "znver4"; + case 0x1a: + // Only one generation in family 1a so far + return "znver5"; + default: + return "znver5"; // Return newest known model here + } + } + else if (brand.startswith("Virtual Apple")) + { + // No AVX. This will change in MacOS 15+, at which point we may revise this. + return "nehalem"; + } + +#elif defined(ARCH_ARM64) + // TODO: Read the data from /proc/cpuinfo. ARM CPU registers are not accessible from usermode. + // This will be a pain when supporting snapdragon on windows but we'll cross that bridge when we get there. + // Require at least armv8-2a. Older chips are going to be useless anyway. + return "cortex-a78"; +#endif + + // Failed to guess, use generic fallback + return "generic"; +} + #endif // LLVM_AVAILABLE diff --git a/rpcs3/Emu/CPU/CPUTranslator.cpp b/rpcs3/Emu/CPU/CPUTranslator.cpp index fa7f15ff9a..28bc0fc3e5 100644 --- a/rpcs3/Emu/CPU/CPUTranslator.cpp +++ b/rpcs3/Emu/CPU/CPUTranslator.cpp @@ -90,7 +90,13 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin m_context = context; m_engine = &engine; - const auto cpu = m_engine->getTargetMachine()->getTargetCPU(); + auto cpu = m_engine->getTargetMachine()->getTargetCPU(); + + if (cpu == "generic") + { + // Detection failed, try to guess + cpu = fallback_cpu_detection(); + } // Test SSSE3 feature (TODO) if (cpu == "generic" ||