1#include <TargetConditionals.h> 2#if TARGET_OS_OSX || TARGET_OS_IPHONE 3#include <sys/sysctl.h> 4 5#if __has_include(<arm/cpu_capabilities_public.h>) 6#include <arm/cpu_capabilities_public.h> 7#define HAS_CPU_CAPABILITIES_PUBLIC_H 1 8 9// FB13964283 - A few of these didn't make it into the public SDK yet. 10#ifndef CAP_BIT_FEAT_SME 11#define CAP_BIT_FEAT_SME 40 12#endif 13#ifndef CAP_BIT_FEAT_SME2 14#define CAP_BIT_FEAT_SME2 41 15#endif 16#ifndef CAP_BIT_FEAT_SME_F64F64 17#define CAP_BIT_FEAT_SME_F64F64 42 18#endif 19#ifndef CAP_BIT_FEAT_SME_I16I64 20#define CAP_BIT_FEAT_SME_I16I64 43 21#endif 22 23#endif 24 25static bool isKnownAndSupported(const char *name) { 26 int32_t val = 0; 27 size_t size = sizeof(val); 28 if (sysctlbyname(name, &val, &size, NULL, 0)) 29 return false; 30 return val; 31} 32 33static uint64_t deriveImplicitFeatures(uint64_t features) { 34 // FEAT_SSBS2 implies FEAT_SSBS 35 if ((1ULL << FEAT_SSBS2) & features) 36 features |= (1ULL << FEAT_SSBS); 37 38 // FEAT_FP is always enabled 39 features |= (1ULL << FEAT_FP); 40 41 features |= (1ULL << FEAT_INIT); 42 43 return features; 44} 45 46void __init_cpu_features_resolver(void) { 47 // On Darwin platforms, this may be called concurrently by multiple threads 48 // because the resolvers that use it are called lazily at runtime (unlike on 49 // ELF platforms, where IFuncs are resolved serially at load time). This 50 // function's effect on __aarch64_cpu_features must be idempotent. 51 52 if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) 53 return; 54 55 uint64_t features = 0; 56 57#ifdef HAS_CPU_CAPABILITIES_PUBLIC_H 58 uint8_t feats_bitvec[(CAP_BIT_NB + 7) / 8] = {0}; 59 size_t len = sizeof(feats_bitvec); 60 // When hw.optional.arm.feats is available (macOS 15.0+, iOS 18.0+), use the 61 // fast path to get all the feature bits, otherwise fall back to the slow 62 // ~20-something sysctls path. 63 if (!sysctlbyname("hw.optional.arm.caps", &feats_bitvec, &len, 0, 0)) { 64 65#define CHECK_BIT(FROM, TO) \ 66 do { \ 67 if (feats_bitvec[FROM / 8] & (1u << ((FROM) & 7))) { \ 68 features |= (1ULL << TO); \ 69 } \ 70 } while (0) 71 72 CHECK_BIT(CAP_BIT_FEAT_FlagM, FEAT_FLAGM); 73 CHECK_BIT(CAP_BIT_FEAT_FlagM2, FEAT_FLAGM2); 74 CHECK_BIT(CAP_BIT_FEAT_FHM, FEAT_FP16FML); 75 CHECK_BIT(CAP_BIT_FEAT_DotProd, FEAT_DOTPROD); 76 CHECK_BIT(CAP_BIT_FEAT_SHA3, FEAT_SHA3); 77 CHECK_BIT(CAP_BIT_FEAT_RDM, FEAT_RDM); 78 CHECK_BIT(CAP_BIT_FEAT_LSE, FEAT_LSE); 79 CHECK_BIT(CAP_BIT_FEAT_SHA256, FEAT_SHA2); 80 CHECK_BIT(CAP_BIT_FEAT_SHA1, FEAT_SHA1); 81 CHECK_BIT(CAP_BIT_FEAT_AES, FEAT_AES); 82 CHECK_BIT(CAP_BIT_FEAT_PMULL, FEAT_PMULL); 83 CHECK_BIT(CAP_BIT_FEAT_SPECRES, FEAT_PREDRES); 84 CHECK_BIT(CAP_BIT_FEAT_SB, FEAT_SB); 85 CHECK_BIT(CAP_BIT_FEAT_FRINTTS, FEAT_FRINTTS); 86 CHECK_BIT(CAP_BIT_FEAT_LRCPC, FEAT_RCPC); 87 CHECK_BIT(CAP_BIT_FEAT_LRCPC2, FEAT_RCPC2); 88 CHECK_BIT(CAP_BIT_FEAT_FCMA, FEAT_FCMA); 89 CHECK_BIT(CAP_BIT_FEAT_JSCVT, FEAT_JSCVT); 90 CHECK_BIT(CAP_BIT_FEAT_DPB, FEAT_DPB); 91 CHECK_BIT(CAP_BIT_FEAT_DPB2, FEAT_DPB2); 92 CHECK_BIT(CAP_BIT_FEAT_BF16, FEAT_BF16); 93 CHECK_BIT(CAP_BIT_FEAT_I8MM, FEAT_I8MM); 94 CHECK_BIT(CAP_BIT_FEAT_DIT, FEAT_DIT); 95 CHECK_BIT(CAP_BIT_FEAT_FP16, FEAT_FP16); 96 CHECK_BIT(CAP_BIT_FEAT_SSBS, FEAT_SSBS2); 97 CHECK_BIT(CAP_BIT_FEAT_BTI, FEAT_BTI); 98 CHECK_BIT(CAP_BIT_AdvSIMD, FEAT_SIMD); 99 CHECK_BIT(CAP_BIT_CRC32, FEAT_CRC); 100 CHECK_BIT(CAP_BIT_FEAT_SME, FEAT_SME); 101 CHECK_BIT(CAP_BIT_FEAT_SME2, FEAT_SME2); 102 CHECK_BIT(CAP_BIT_FEAT_SME_F64F64, FEAT_SME_F64); 103 CHECK_BIT(CAP_BIT_FEAT_SME_I16I64, FEAT_SME_I64); 104 105 features = deriveImplicitFeatures(features); 106 107 __atomic_store(&__aarch64_cpu_features.features, &features, 108 __ATOMIC_RELAXED); 109 return; 110 } 111#endif 112 113 // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics 114 static const struct { 115 const char *sysctl_name; 116 enum CPUFeatures feature; 117 } feature_checks[] = { 118 {"hw.optional.arm.FEAT_FlagM", FEAT_FLAGM}, 119 {"hw.optional.arm.FEAT_FlagM2", FEAT_FLAGM2}, 120 {"hw.optional.arm.FEAT_FHM", FEAT_FP16FML}, 121 {"hw.optional.arm.FEAT_DotProd", FEAT_DOTPROD}, 122 {"hw.optional.arm.FEAT_RDM", FEAT_RDM}, 123 {"hw.optional.arm.FEAT_LSE", FEAT_LSE}, 124 {"hw.optional.AdvSIMD", FEAT_SIMD}, 125 {"hw.optional.armv8_crc32", FEAT_CRC}, 126 {"hw.optional.arm.FEAT_SHA1", FEAT_SHA1}, 127 {"hw.optional.arm.FEAT_SHA256", FEAT_SHA2}, 128 {"hw.optional.arm.FEAT_SHA3", FEAT_SHA3}, 129 {"hw.optional.arm.FEAT_AES", FEAT_AES}, 130 {"hw.optional.arm.FEAT_PMULL", FEAT_PMULL}, 131 {"hw.optional.arm.FEAT_FP16", FEAT_FP16}, 132 {"hw.optional.arm.FEAT_DIT", FEAT_DIT}, 133 {"hw.optional.arm.FEAT_DPB", FEAT_DPB}, 134 {"hw.optional.arm.FEAT_DPB2", FEAT_DPB2}, 135 {"hw.optional.arm.FEAT_JSCVT", FEAT_JSCVT}, 136 {"hw.optional.arm.FEAT_FCMA", FEAT_FCMA}, 137 {"hw.optional.arm.FEAT_LRCPC", FEAT_RCPC}, 138 {"hw.optional.arm.FEAT_LRCPC2", FEAT_RCPC2}, 139 {"hw.optional.arm.FEAT_FRINTTS", FEAT_FRINTTS}, 140 {"hw.optional.arm.FEAT_I8MM", FEAT_I8MM}, 141 {"hw.optional.arm.FEAT_BF16", FEAT_BF16}, 142 {"hw.optional.arm.FEAT_SB", FEAT_SB}, 143 {"hw.optional.arm.FEAT_SPECRES", FEAT_PREDRES}, 144 {"hw.optional.arm.FEAT_SSBS", FEAT_SSBS2}, 145 {"hw.optional.arm.FEAT_BTI", FEAT_BTI}, 146 }; 147 148 for (size_t I = 0, E = sizeof(feature_checks) / sizeof(feature_checks[0]); 149 I != E; ++I) 150 if (isKnownAndSupported(feature_checks[I].sysctl_name)) 151 features |= (1ULL << feature_checks[I].feature); 152 153 features = deriveImplicitFeatures(features); 154 155 __atomic_store(&__aarch64_cpu_features.features, &features, 156 __ATOMIC_RELAXED); 157} 158 159#endif // TARGET_OS_OSX || TARGET_OS_IPHONE 160