#pragma once #if defined(__aarch64__) || defined(_M_ARM64) #if defined(__linux__) #include #include #if !defined(HWCAP2_SVE2) #define HWCAP2_SVE2 (1ULL << 1) #endif #if !defined(HWCAP_FPHP) #define HWCAP_FPHP (1 << 9) #endif #if !defined(HWCAP_ASIMDHP) #define HWCAP_ASIMDHP (1 << 10) #endif #if !defined(HWCAP2_I8MM) #define HWCAP2_I8MM (1ULL << 13) #endif #if !defined(HWCAP_ASIMDDP) #define HWCAP_ASIMDDP (1 << 20) #endif #if !defined(HWCAP_SVE) #define HWCAP_SVE (1 << 22) #endif #if !defined(HWCAP2_SME) #define HWCAP2_SME (1ULL << 23) #endif #if !defined(HWCAP2_SME2) #define HWCAP2_SME2 (1ULL << 37) #endif #if !defined(PR_SVE_GET_VL) #define PR_SVE_GET_VL 51 #endif #if !defined(PR_SVE_VL_LEN_MASK) #define PR_SVE_VL_LEN_MASK 0xffff #endif #elif defined(__APPLE__) #include #elif defined(_WIN32) #include #if !defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43 #endif #if !defined(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) #define PF_ARM_SVE_INSTRUCTIONS_AVAILABLE 46 #endif #if !defined(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) #define PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE 47 #endif #if !defined(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE 66 #endif #if !defined(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE) #define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE 67 #endif #if !defined(PF_ARM_SME_INSTRUCTIONS_AVAILABLE) #define PF_ARM_SME_INSTRUCTIONS_AVAILABLE 70 #endif #if !defined(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE) #define PF_ARM_SME2_INSTRUCTIONS_AVAILABLE 71 #endif #endif typedef struct ggml_feats_arch64_runtime { bool has_dotprod; bool has_fp16; bool has_sve; bool has_sve2; bool has_i8mm; bool has_sme; bool has_sme2; int sve_cnt; } ggml_feats_arch64_runtime_t; static inline ggml_feats_arch64_runtime_t ggml_feats_get_arch64_runtime(void) { ggml_feats_arch64_runtime_t runtime_feat = {}; #if defined(__linux__) const unsigned long hwcap = getauxval(AT_HWCAP); const unsigned long hwcap2 = getauxval(AT_HWCAP2); runtime_feat.has_dotprod = !!(hwcap & HWCAP_ASIMDDP); runtime_feat.has_fp16 = !!(hwcap & HWCAP_FPHP) && !!(hwcap & HWCAP_ASIMDHP);; runtime_feat.has_sve = !!(hwcap & HWCAP_SVE); runtime_feat.has_sve2 = !!(hwcap2 & HWCAP2_SVE2); runtime_feat.has_i8mm = !!(hwcap2 & HWCAP2_I8MM); runtime_feat.has_sme = !!(hwcap2 & HWCAP2_SME); runtime_feat.has_sme2 = !!(hwcap2 & HWCAP2_SME2); if (runtime_feat.has_sve) { const int vl = prctl(PR_SVE_GET_VL); if (vl >= 0) { runtime_feat.sve_cnt = vl & PR_SVE_VL_LEN_MASK; } } #elif defined(__APPLE__) int oldp = 0; size_t size = sizeof(oldp); if (sysctlbyname("hw.optional.arm.FEAT_DotProd", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_dotprod = static_cast(oldp); } if (sysctlbyname("hw.optional.arm.FEAT_FP16", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_fp16 = static_cast(oldp); } if (sysctlbyname("hw.optional.arm.FEAT_SVE", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_sve = static_cast(oldp); } if (sysctlbyname("hw.optional.arm.FEAT_SVE2", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_sve2 = static_cast(oldp); } if (sysctlbyname("hw.optional.arm.FEAT_I8MM", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_i8mm = static_cast(oldp); } if (sysctlbyname("hw.optional.arm.FEAT_SME", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_sme = static_cast(oldp); } if (sysctlbyname("hw.optional.arm.FEAT_SME2", &oldp, &size, nullptr, 0) == 0) { runtime_feat.has_sme2 = static_cast(oldp); } // Apple does not support userspace non-streaming SVE; keep SVE vector length unknown. runtime_feat.sve_cnt = 0; #elif defined (_WIN32) runtime_feat.has_dotprod = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != 0; runtime_feat.has_fp16 = IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE) != 0; runtime_feat.has_sve = IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) != 0; runtime_feat.has_sve2 = IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) != 0; runtime_feat.has_i8mm = IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE) != 0; runtime_feat.has_sme = IsProcessorFeaturePresent(PF_ARM_SME_INSTRUCTIONS_AVAILABLE) != 0; runtime_feat.has_sme2 = IsProcessorFeaturePresent(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE) != 0; // Windows exposes SVE feature presence, but not the runtime SVE vector length here. runtime_feat.sve_cnt = 0; #endif return runtime_feat; } #endif // defined(__aarch64__) || defined(_M_ARM64)