Add riscv half-precision floating point detection (#375) Add cpuinfo_has_riscv_zfh() and cpuinfo_has_riscv_zvfh for fp16 detection. The motivation here is to enable this runtime detection support in xnnpack for its rvv fp16 kernels. (xnnpack uses this library) GitOrigin-RevId: d05fbcd57dc096718c4979e7c054e628f1f3520b Change-Id: I6cbab6d7c0fb2eb1a605edfeb22a4df2684c8d20
diff --git a/include/cpuinfo.h b/include/cpuinfo.h index a441bb1..321998c 100644 --- a/include/cpuinfo.h +++ b/include/cpuinfo.h
@@ -2232,6 +2232,12 @@ bool c; /* Vector Extension. */ bool v; + + /* ISA Extensions */ + /* Half-Precision Floating-Point Extension. */ + bool zfh; + /* Half-Precision Floating-Point Vector Extension. */ + bool zvfh; }; extern struct cpuinfo_riscv_isa cpuinfo_isa; @@ -2307,6 +2313,22 @@ #endif } +static inline bool cpuinfo_has_riscv_zfh(void) { +#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 + return cpuinfo_isa.zfh; +#else + return false; +#endif +} + +static inline bool cpuinfo_has_riscv_zvfh(void) { +#if CPUINFO_ARCH_RISCV32 || CPUINFO_ARCH_RISCV64 + return cpuinfo_isa.zvfh; +#else + return false; +#endif +} + const struct cpuinfo_processor* CPUINFO_ABI cpuinfo_get_processors(void); const struct cpuinfo_core* CPUINFO_ABI cpuinfo_get_cores(void); const struct cpuinfo_cluster* CPUINFO_ABI cpuinfo_get_clusters(void);
diff --git a/src/riscv/linux/api.h b/src/riscv/linux/api.h index 829de84..1c356bf 100644 --- a/src/riscv/linux/api.h +++ b/src/riscv/linux/api.h
@@ -61,11 +61,13 @@ * @param[processor] - The Linux ID of the target processor. * @param[vendor] - Reference to the cpuinfo_vendor to populate. * @param[uarch] - Reference to the cpuinfo_uarch to populate. + * @param[isa] - Reference to the cpuinfo_riscv_isa to populate isa extensions. */ CPUINFO_INTERNAL void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe( uint32_t processor, enum cpuinfo_vendor vendor[restrict static 1], - enum cpuinfo_uarch uarch[restrict static 1]); + enum cpuinfo_uarch uarch[restrict static 1], + struct cpuinfo_riscv_isa isa[restrict static 1]); /* Used to determine which uarch is associated with the current thread. */ extern CPUINFO_INTERNAL const uint32_t* cpuinfo_linux_cpu_to_uarch_index_map;
diff --git a/src/riscv/linux/init.c b/src/riscv/linux/init.c index 9ab3d6e..45168c7 100644 --- a/src/riscv/linux/init.c +++ b/src/riscv/linux/init.c
@@ -6,7 +6,7 @@ #include <riscv/linux/api.h> /* ISA structure to hold supported extensions. */ -struct cpuinfo_riscv_isa cpuinfo_isa; +struct cpuinfo_riscv_isa cpuinfo_isa = {0}; /* Helper function to bitmask flags and ensure operator precedence. */ static inline bool bitmask_all(uint32_t flags, uint32_t mask) { @@ -320,7 +320,8 @@ cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe( processor, &riscv_linux_processors[processor].core.vendor, - &riscv_linux_processors[processor].core.uarch); + &riscv_linux_processors[processor].core.uarch, + &cpuinfo_isa); /* Populate frequency information of this core. */ uint32_t frequency = cpuinfo_linux_get_processor_cur_frequency(processor);
diff --git a/src/riscv/linux/riscv-hw.c b/src/riscv/linux/riscv-hw.c index 63a92e2..f820086 100644 --- a/src/riscv/linux/riscv-hw.c +++ b/src/riscv/linux/riscv-hw.c
@@ -53,6 +53,30 @@ #define RISCV_HWPROBE_EXT_ZBB (1 << 4) #define RISCV_HWPROBE_EXT_ZBS (1 << 5) #define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -72,7 +96,8 @@ void cpuinfo_riscv_linux_decode_vendor_uarch_from_hwprobe( uint32_t processor, enum cpuinfo_vendor vendor[restrict static 1], - enum cpuinfo_uarch uarch[restrict static 1]) { + enum cpuinfo_uarch uarch[restrict static 1], + struct cpuinfo_riscv_isa isa[restrict static 1]) { struct riscv_hwprobe pairs[] = { { .key = RISCV_HWPROBE_KEY_MVENDORID, @@ -83,6 +108,9 @@ { .key = RISCV_HWPROBE_KEY_MIMPID, }, + { + .key = RISCV_HWPROBE_KEY_IMA_EXT_0, + }, }; const size_t pairs_count = sizeof(pairs) / sizeof(struct riscv_hwprobe); @@ -128,6 +156,7 @@ uint32_t vendor_id = 0; uint32_t arch_id = 0; uint32_t imp_id = 0; + uint64_t ima_ext_0 = 0; for (size_t pair = 0; pair < pairs_count; pair++) { switch (pairs[pair].key) { case RISCV_HWPROBE_KEY_MVENDORID: @@ -139,6 +168,9 @@ case RISCV_HWPROBE_KEY_MIMPID: imp_id = pairs[pair].value; break; + case RISCV_HWPROBE_KEY_IMA_EXT_0: + ima_ext_0 = pairs[pair].value; + break; default: /* The key value may be -1 if unsupported. */ break; @@ -146,6 +178,16 @@ } cpuinfo_riscv_decode_vendor_uarch(vendor_id, arch_id, imp_id, vendor, uarch); + /* Parse ISA extensions retrieved. */ + if (ima_ext_0 != 0) { + if (ima_ext_0 & RISCV_HWPROBE_EXT_ZFH) { + isa->zfh = true; + } + if (ima_ext_0 & RISCV_HWPROBE_EXT_ZVFH) { + isa->zvfh = true; + } + } + cleanup: CPU_FREE(cpu_set); }
diff --git a/tools/isa-info.c b/tools/isa-info.c index a7e387a..9511e8b 100644 --- a/tools/isa-info.c +++ b/tools/isa-info.c
@@ -199,7 +199,9 @@ printf("\tAtomics: %s\n", cpuinfo_has_riscv_a() ? "yes" : "no"); printf("\tSingle-Precision Floating-Point: %s\n", cpuinfo_has_riscv_f() ? "yes" : "no"); printf("\tDouble-Precision Floating-Point: %s\n", cpuinfo_has_riscv_d() ? "yes" : "no"); + printf("\tHalf-Precision Floating-Point: %s\n", cpuinfo_has_riscv_zfh() ? "yes" : "no"); printf("\tCompressed: %s\n", cpuinfo_has_riscv_c() ? "yes" : "no"); printf("\tVector: %s\n", cpuinfo_has_riscv_v() ? "yes" : "no"); + printf("\tVector Half-Precision Floating-Point: %s\n", cpuinfo_has_riscv_zvfh() ? "yes" : "no"); #endif }