From 68bbb2980e45384454a0128d8264b3de0640a859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 26 Aug 2025 14:43:36 +0800 Subject: [PATCH] CPU (macOS): detects march on Apple Silicon --- src/detection/cpu/cpu.c | 130 +++++++++++++++++++++++++++++++++- src/detection/cpu/cpu_apple.c | 2 +- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/src/detection/cpu/cpu.c b/src/detection/cpu/cpu.c index cb916a2d6..36578a0bf 100644 --- a/src/detection/cpu/cpu.c +++ b/src/detection/cpu/cpu.c @@ -294,11 +294,135 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu) } } } -#else -void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu) +#elif __APPLE__ +#include +#include + +#ifndef CAP_BIT_AdvSIMD +#define CAP_BIT_AdvSIMD 49 +#endif +#ifndef CAP_BIT_AdvSIMD_HPFPCvt +#define CAP_BIT_AdvSIMD_HPFPCvt 50 +#endif +#ifndef CAP_BIT_FEAT_CRC32 +#define CAP_BIT_FEAT_CRC32 51 +#endif +#ifndef CAP_BIT_FEAT_HBC +#define CAP_BIT_FEAT_HBC 64 +#endif +#ifndef CAP_BIT_FEAT_CSSC +#define CAP_BIT_FEAT_CSSC 67 +#endif + +void ffCPUDetectByCpuid(FFCPUResult* cpu) { - // Unsupported platform + uint64_t caps[2] = {0}; // 80-bit capability mask, split into two 64-bit values + size_t size = sizeof(caps); + + if (sysctlbyname("hw.optional.arm.caps", caps, &size, NULL, 0) != 0) return; + + // Helper macro to test bit in 80-bit capability mask + #define FF_HAS_CAP(bit) \ + (((bit) < 64) ? ((caps[0] >> (bit)) & 1ULL) : ((caps[1] >> ((bit) - 64U)) & 1ULL)) + + cpu->march = "unknown"; + + // ARMv8-A + bool has_fp = FF_HAS_CAP(CAP_BIT_AdvSIMD_HPFPCvt); // Full FP16 support (implies FP/ASIMD) + bool has_asimd = FF_HAS_CAP(CAP_BIT_AdvSIMD); // Advanced SIMD (NEON) + + // ARMv8.1-A + bool has_lse = FF_HAS_CAP(CAP_BIT_FEAT_LSE); // Large System Extensions, optional in v8.0 + bool has_crc32 = FF_HAS_CAP(CAP_BIT_FEAT_CRC32); // CRC32 instructions, optional in v8.0 + bool has_rdm = FF_HAS_CAP(CAP_BIT_FEAT_RDM); // AdvSIMD rounding double multiply accumulate, optional in v8.0 + + // ARMv8.2-A + bool has_fp16 = FF_HAS_CAP(CAP_BIT_FEAT_FP16); // Half-precision FP support, optional + bool has_dpb = FF_HAS_CAP(CAP_BIT_FEAT_DPB); // DC CVAP, optional from v8.1 + + // ARMv8.3-A + bool has_pauth = FF_HAS_CAP(CAP_BIT_FEAT_PAuth); // Pointer Authentication (PAC), optional from v8.2 + bool has_lrcpc = FF_HAS_CAP(CAP_BIT_FEAT_LRCPC); // LDAPR/LR with RCPC semantics, optional from v8.2 + bool has_fcma = FF_HAS_CAP(CAP_BIT_FEAT_FCMA); // Complex number multiply-add, optional from v8.2 + bool has_jscvt = FF_HAS_CAP(CAP_BIT_FEAT_JSCVT); // JavaScript-style conversion (FJCVTZS), optional from v8.2 + + // ARMv8.4-A + bool has_lse2 = FF_HAS_CAP(CAP_BIT_FEAT_LSE2); // Large System Extensions version 2, optional from v8.2 + bool has_dit = FF_HAS_CAP(CAP_BIT_FEAT_DIT); // Data Independent Timing, optional from v8.3 + bool has_flagm = FF_HAS_CAP(CAP_BIT_FEAT_FlagM); // Flag manipulation (FMOV/FCVT), optional from v8.1 + bool has_lrcpc2 = FF_HAS_CAP(CAP_BIT_FEAT_LRCPC2); // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2 + + // ARMv8.5-A + bool has_bti = FF_HAS_CAP(CAP_BIT_FEAT_BTI); // Branch Target Identification, optional from v8.4 + bool has_sb = FF_HAS_CAP(CAP_BIT_FEAT_SB); // Speculative Barrier, optional from v8.0 + bool has_dpb2 = FF_HAS_CAP(CAP_BIT_FEAT_DPB2); // DC CVADP (DPB2), optional from v8.1 + bool has_flagm2 = FF_HAS_CAP(CAP_BIT_FEAT_FlagM2); // Enhanced FlagM, optional from v8.4 + bool has_frintts = FF_HAS_CAP(CAP_BIT_FEAT_FRINTTS); // Floating-point to integer instructions, optional from v8.4 + + // ARMv9.0-A + bool has_sve2 = false; // Not exposed and not supported by Apple M4 + + // ARMv9.1-A + // ARMv8.6-A + bool has_bf16 = FF_HAS_CAP(CAP_BIT_FEAT_BF16); // Brain float16, optional from v8.2 + bool has_i8mm = FF_HAS_CAP(CAP_BIT_FEAT_I8MM); // Int8 Matrix Multiply, optional from v8.1 + + // ARMv8.7-A + bool has_afp = FF_HAS_CAP(CAP_BIT_FEAT_AFP); // Alternate FP16 (FEXPA), optional from v8.6 + + // ARMv9.2-A + bool has_sme = FF_HAS_CAP(CAP_BIT_FEAT_SME); // Scalable Matrix Extension, optional from v9.2 + + // ARMv9.3-A + bool has_sme2 = FF_HAS_CAP(CAP_BIT_FEAT_SME2); // SME2, optional from v9.2 + + // ARMv8.8-A + bool has_hbc = FF_HAS_CAP(CAP_BIT_FEAT_HBC); // Hinted conditional branches, optional from v8.7 + + // ARMv8.9-A + bool has_cssc = FF_HAS_CAP(CAP_BIT_FEAT_CSSC); // Common Short String Compare, optional from v8.7 + + // ARMv9.4-A+ are not exposed yet + + if (has_sve2 || has_sme) { + // ARMv9 family + if (has_sme2) { + cpu->march = "ARMv9.3-A"; + } else if (has_sme) { + cpu->march = "ARMv9.2-A"; + } else if (has_i8mm && has_bf16) { + cpu->march = "ARMv9.1-A"; + } else { + cpu->march = "ARMv9.0-A"; + } + } else { + // ARMv8 family + if (has_cssc) { + cpu->march = "ARMv8.9-A"; + } else if (has_hbc) { + cpu->march = "ARMv8.8-A"; + } else if (has_afp) { + cpu->march = "ARMv8.7-A"; + } else if (has_i8mm && has_bf16) { + cpu->march = "ARMv8.6-A"; + } else if (has_bti && has_sb && has_dpb2 && has_flagm2 && has_frintts) { + cpu->march = "ARMv8.5-A"; + } else if (has_lse2 && has_dit && has_flagm && has_lrcpc2) { + cpu->march = "ARMv8.4-A"; + } else if (has_pauth && has_lrcpc && has_fcma && has_jscvt) { + cpu->march = "ARMv8.3-A"; + } else if (has_fp16 && has_dpb) { + cpu->march = "ARMv8.2-A"; + } else if (has_lse && has_crc32 && has_rdm) { + cpu->march = "ARMv8.1-A"; + } else if (has_asimd && has_fp) { + cpu->march = "ARMv8-A"; + } + } + + #undef HAS_CAP } +#else #endif // __linux__ #else diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index b6f2a9036..7a09d4c7b 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -72,7 +72,6 @@ static const char* detectFrequency(FFCPUResult* cpu) #else static const char* detectFrequency(FFCPUResult* cpu) { - ffCPUDetectByCpuid(cpu); cpu->frequencyBase = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency", 0) / 1000 / 1000); cpu->frequencyMax = (uint32_t) (ffSysctlGetInt64("hw.cpufrequency_max", 0) / 1000 / 1000); if(cpu->frequencyBase == 0) @@ -127,6 +126,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) if(cpu->coresOnline == 1) cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1); + ffCPUDetectByCpuid(cpu); detectFrequency(cpu); if (options->showPeCoreCount) detectCoreCount(cpu);