Implement missing ISA feature flags for ARM64/Windows (#333)
* implement SVE/SVE2 and list out the missing feature flags
* Implement most of the ISA feature flags
* Update notes
* Add more flags to isa info
* Additional flags
* Add conservative values for SVE
* clang formatting
* format headers
diff --git a/src/arm/windows/init.c b/src/arm/windows/init.c
index b5559ad..5c0a5f3 100644
--- a/src/arm/windows/init.c
+++ b/src/arm/windows/init.c
@@ -133,6 +133,26 @@
return info;
}
+/* https://developer.arm.com/documentation/ddi0601/2024-06/AArch64-Registers
+ CP 4000: MIDR_EL1
+ CP 4020: ID_AA64PFR0_EL1
+ CP 4021: ID_AA64PFR1_EL1
+ CP 4028: ID_AA64DFR0_EL1
+ CP 4029: ID_AA64DFR1_EL1
+ CP 402C: ID_AA64AFR0_EL1
+ CP 402D: ID_AA64AFR1_EL1
+ CP 4030: ID_AA64ISAR0_EL1
+ CP 4031: ID_AA64ISAR1_EL1
+ CP 4038: ID_AA64MMFR0_EL1
+ CP 4039: ID_AA64MMFR1_EL1
+ CP 403A: ID_AA64MMFR2_EL1
+ CP 4080: ?
+ CP 4081: ?
+ CP 4100: ?
+ CP 4510: ?
+ CP 5801: ?
+ */
+
static struct woa_chip_info* get_system_info_from_registry(void) {
wchar_t* text_buffer = NULL;
LPCWSTR cpu0_subkey = L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
@@ -194,21 +214,40 @@
const bool dotprod = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != 0;
cpuinfo_isa.dot = dotprod;
- SYSTEM_INFO system_info;
- GetSystemInfo(&system_info);
- switch (system_info.wProcessorLevel) {
- case 0x803: // Kryo 385 Silver (Snapdragon 850)
- cpuinfo_isa.fp16arith = dotprod;
- cpuinfo_isa.rdm = dotprod;
- break;
- default:
- // Assume that Dot Product support implies FP16
- // arithmetics and RDM support. ARM manuals don't
- // guarantee that, but it holds in practice.
- cpuinfo_isa.fp16arith = dotprod;
- cpuinfo_isa.rdm = dotprod;
- break;
- }
+ cpuinfo_isa.sve = IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.sve2 = IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.i8mm = IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.jscvt = IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.fcma = IsProcessorFeaturePresent(PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE) != 0;
+ // FEAT_FP16 Implies FEAT_FHM in 8.4
+ // https://developer.arm.com/documentation/109697/2025_09/Feature-descriptions/The-Armv8-4-architecture-extension?lang=en
+ cpuinfo_isa.fhm = IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.fp16arith = cpuinfo_isa.fhm;
+
+ cpuinfo_isa.sme = IsProcessorFeaturePresent(PF_ARM_SME_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.sme2 = IsProcessorFeaturePresent(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.sme2p1 = IsProcessorFeaturePresent(PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.sme_b16b16 = IsProcessorFeaturePresent(PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE) != 0;
+ cpuinfo_isa.sme_f16f16 = IsProcessorFeaturePresent(PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE) != 0;
+
+ // TODO: Add when available in Windows SDK
+ // - sme_i16i32
+ // - sme_bi32i32
+
+ cpuinfo_isa.bf16 = IsProcessorFeaturePresent(PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE) != 0;
+
+ // TODO: This is not available in the Windows SDK yet , so conservatively go with the lowest value (128 bits)
+ // https://developer.arm.com/documentation/101427/0102/Register-descriptions/Scalable-vector-extensions--SVE--registers/ZCR-EL1--SVE-Control-Register--EL1
+ cpuinfo_isa.svelen =
+ cpuinfo_isa.sve ? 128 / 8 : 0; // This value is in bytes, see cpuinfo_get_max_arm_sve_length
+
+ // TODO : Fetch from feature registers when available
+ // cpuinfo_isa.smelen = 0;
+
+ // Assume that Dot Product support implies FP16
+ // arithmetics and RDM support. ARM manuals don't
+ // guarantee that, but it holds in practice.
+ cpuinfo_isa.rdm = dotprod;
/* Windows API reports all or nothing for cryptographic instructions. */
const bool crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0;
diff --git a/src/arm/windows/windows-arm-init.h b/src/arm/windows/windows-arm-init.h
index 52dd180..3c49284 100644
--- a/src/arm/windows/windows-arm-init.h
+++ b/src/arm/windows/windows-arm-init.h
@@ -19,3 +19,63 @@
};
bool cpu_info_init_by_logical_sys_info(const struct woa_chip_info* chip_info, enum cpuinfo_vendor vendor);
+
+#ifndef PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE (27)
+#endif
+
+#ifndef PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE (34)
+#endif
+
+#ifndef PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE (44)
+#endif
+
+#ifndef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SVE_INSTRUCTIONS_AVAILABLE (46)
+#endif
+
+#ifndef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE (47)
+#endif
+
+#ifndef PF_ARM_SME_BI32I32_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME_BI32I32_INSTRUCTIONS_AVAILABLE (55)
+#endif
+
+#ifndef PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE (66)
+#endif
+
+#ifndef PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE (68)
+#endif
+
+#ifndef PF_ARM_SME_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME_INSTRUCTIONS_AVAILABLE (70)
+#endif
+
+#ifndef PF_ARM_SME2_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME2_INSTRUCTIONS_AVAILABLE (71)
+#endif
+
+#ifndef PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE (72)
+#endif
+
+#ifndef PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE (73)
+#endif
+
+#ifndef PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE (83)
+#endif
+
+#ifndef PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE (84)
+#endif
+
+#ifndef PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE
+#define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE (67)
+#endif
diff --git a/tools/isa-info.c b/tools/isa-info.c
index 740be64..a7e387a 100644
--- a/tools/isa-info.c
+++ b/tools/isa-info.c
@@ -175,6 +175,11 @@
printf("\tARM SVE 2: %s\n", cpuinfo_has_arm_sve2() ? "yes" : "no");
printf("\tARM SME: %s\n", cpuinfo_has_arm_sme() ? "yes" : "no");
printf("\tARM SME 2: %s\n", cpuinfo_has_arm_sme2() ? "yes" : "no");
+ printf("\tARM SME 2P1: %s\n", cpuinfo_has_arm_sme2p1() ? "yes" : "no");
+ printf("\tARM SME I16I32: %s\n", cpuinfo_has_arm_sme_i16i32() ? "yes" : "no");
+ printf("\tARM SME BI32I32: %s\n", cpuinfo_has_arm_sme_bi32i32() ? "yes" : "no");
+ printf("\tARM SME B16B16: %s\n", cpuinfo_has_arm_sme_b16b16() ? "yes" : "no");
+ printf("\tARM SME F16F16: %s\n", cpuinfo_has_arm_sme_f16f16() ? "yes" : "no");
printf("ARM SVE Capabilities:\n");
printf("\tSVE max length: %d\n", cpuinfo_get_max_arm_sve_length());