x.c
// Demonstrating use of ifunc & target attribute for selective use of ARM extensions
//
// build with e.g., -march=armv9-a x.c
#include <arm_sve.h>
#include <asm/hwcap.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
void fn_basic(void) {
puts("basic function");
// Note: so long as basic cflags don't imply sve, this line will fail to
// compile: uint64_t vl = svcntw ();
}
__attribute__((target("+sve"))) void fn_advanced(void) {
puts("sve using function");
uint64_t vl = svcntw();
printf("vl=%" PRIu64 "\n", vl);
}
#define get_cpu_ftr(id) \
({ \
unsigned long __val; \
asm("mrs %0, " #id : "=r"(__val)); \
__val; \
})
#define print_cpu_ftr(id) \
({ \
unsigned long __val; \
asm("mrs %0, " #id : "=r"(__val)); \
printf("%-20s: 0x%016lx\n", #id, __val); \
})
int sve_level() { return (get_cpu_ftr(ID_AA64ISAR1_EL1) >> 32) & 0xf; }
static void (*resolve_fn(void))(void) {
bool has_sve = sve_level() == 1;
if (has_sve)
return fn_advanced;
return fn_basic;
}
void fn(void) __attribute__((ifunc("resolve_fn")));
int main() {
#ifdef __BUILTIN_CPU_SUPPORTS__
// my compiler does not ... so don't bother trying
printf("has builtin cpu supports");
#endif
if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
fputs("CPUID registers unavailable\n", stderr);
abort();
}
//print_cpu_ftr(ID_AA64ISAR0_EL1);
print_cpu_ftr(ID_AA64ISAR1_EL1);
//print_cpu_ftr(ID_AA64MMFR0_EL1);
//print_cpu_ftr(ID_AA64MMFR1_EL1);
//print_cpu_ftr(ID_AA64PFR0_EL1);
//print_cpu_ftr(ID_AA64PFR1_EL1);
//print_cpu_ftr(ID_AA64DFR0_EL1);
//print_cpu_ftr(ID_AA64DFR1_EL1);
//print_cpu_ftr(MIDR_EL1);
//print_cpu_ftr(MPIDR_EL1);
//print_cpu_ftr(REVIDR_EL1);
printf("sve level %d\n", sve_level());
fn();
}