AArch64: identify Apple M2 Pro/Max and use a concrete -mcpu

The CPU table lacked the Apple M2 Pro/Max cores (MIDR part 0x038/0x039),
so they were reported as "Unidentified cores" and the JIT fell back to a
generic -mcpu=cortex-a78. Add those parts and a new aarch64::get_cpu_llvm_name()
that maps the detected Apple SoC family to the matching LLVM CPU
(apple-m1..m4); fallback_cpu_detection() now uses it so the recompilers get
the correct scheduling model on Apple silicon instead of a generic core.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rad0van 2026-06-06 13:50:57 +02:00
parent 62d32ab45e
commit fd092f3465
3 changed files with 58 additions and 0 deletions

View File

@ -1044,6 +1044,14 @@ const char * fallback_cpu_detection()
return s_result.c_str();
#else
// Prefer a concrete host -mcpu (e.g. apple-m2) so LLVM uses the right scheduling model.
// MIDR_EL1 is exposed via sysfs on Linux; see aarch64::get_cpu_llvm_name().
static const std::string s_mcpu = aarch64::get_cpu_llvm_name();
if (!s_mcpu.empty())
{
return s_mcpu.c_str();
}
// 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.

View File

@ -83,6 +83,8 @@ namespace aarch64
{ 0x61, 0x25, "armv8.5-a", "M1 Pro", "Icestorm" },
{ 0x61, 0x32, "armv8.5-a", "M2", "Avalanche" },
{ 0x61, 0x33, "armv8.5-a", "M2", "Blizzard" },
{ 0x61, 0x38, "armv8.5-a+fp16+bf16+i8mm+dotprod", "M2 Pro/Max", "Avalanche" },
{ 0x61, 0x39, "armv8.5-a+fp16+bf16+i8mm+dotprod", "M2 Pro/Max", "Blizzard" },
// QUALCOMM
{ 0x51, 0x01, "armv8.5-a", "Snapdragon", "X-Elite" },
@ -239,6 +241,40 @@ namespace aarch64
result += suffix;
return result;
}
std::string get_cpu_llvm_name()
{
std::map<u64, int> core_layout;
for (u32 i = 0; i < std::thread::hardware_concurrency(); ++i)
{
const auto midr = read_MIDR_EL1(i);
if (midr == umax)
{
break;
}
core_layout[midr]++;
}
for (const auto& [midr, count] : core_layout)
{
const auto implementer_id = (midr >> 24) & 0xff;
const auto part_id = (midr >> 4) & 0xfff;
const auto part_info = find_cpu_part(implementer_id, part_id);
if (!part_info || implementer_id != 0x61 || !part_info->family)
{
continue;
}
// Map Apple SoC family to an LLVM -mcpu so the JIT schedules for the real microarchitecture.
const std::string family = part_info->family;
if (family.starts_with("M1")) return "apple-m1";
if (family.starts_with("M2")) return "apple-m2";
if (family.starts_with("M3")) return "apple-m3";
if (family.starts_with("M4")) return "apple-m4";
}
return {};
}
#else
static std::string sysctl_s(const std::string_view& variable_name)
{
@ -297,5 +333,15 @@ namespace aarch64
return fmt::format("%s (%lluP+%lluE)", brand, pcores, ecores);
}
std::string get_cpu_llvm_name()
{
const auto brand = sysctl_s("machdep.cpu.brand_string");
if (brand.find("M1") != umax) return "apple-m1";
if (brand.find("M2") != umax) return "apple-m2";
if (brand.find("M3") != umax) return "apple-m3";
if (brand.find("M4") != umax) return "apple-m4";
return {};
}
#endif
}

View File

@ -39,4 +39,8 @@ namespace aarch64
std::string get_cpu_name();
std::string get_cpu_brand();
// Returns a concrete LLVM -mcpu name for the host (e.g. "apple-m2") or "" if unknown.
// Used to give the JIT the correct scheduling model instead of a generic fallback.
std::string get_cpu_llvm_name();
}