util: Add RISC-V vector extension probe in cpuinfo

Add support for probing RISC-V vector extension availability in
the backend. This information will be used when deciding whether
to use vector instructions in code generation.

Cache lg2(vlenb) for the backend. The storing of lg2(vlenb) means
we can convert all of the division into subtraction.

While the compiler doesn't support RISCV_HWPROBE_EXT_ZVE64X,
we use RISCV_HWPROBE_IMA_V instead. RISCV_HWPROBE_IMA_V is more
strictly constrainted than RISCV_HWPROBE_EXT_ZVE64X. At least in
current QEMU implemenation, the V vector extension depends on the
zve64d extension.

Signed-off-by: TANG Tiancheng <tangtiancheng.ttc@alibaba-inc.com>
Reviewed-by: Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
Tested-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Message-ID: <20241007025700.47259-2-zhiwei_liu@linux.alibaba.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
TANG Tiancheng 2024-10-07 10:56:49 +08:00 committed by Richard Henderson
parent be46e0bf14
commit f7230e09b1
2 changed files with 35 additions and 1 deletions

View File

@ -10,9 +10,11 @@
#define CPUINFO_ZBA (1u << 1) #define CPUINFO_ZBA (1u << 1)
#define CPUINFO_ZBB (1u << 2) #define CPUINFO_ZBB (1u << 2)
#define CPUINFO_ZICOND (1u << 3) #define CPUINFO_ZICOND (1u << 3)
#define CPUINFO_ZVE64X (1u << 4)
/* Initialized with a constructor. */ /* Initialized with a constructor. */
extern unsigned cpuinfo; extern unsigned cpuinfo;
extern unsigned riscv_lg2_vlenb;
/* /*
* We cannot rely on constructor ordering, so other constructors must * We cannot rely on constructor ordering, so other constructors must

View File

@ -4,6 +4,7 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/host-utils.h"
#include "host/cpuinfo.h" #include "host/cpuinfo.h"
#ifdef CONFIG_ASM_HWPROBE_H #ifdef CONFIG_ASM_HWPROBE_H
@ -13,6 +14,7 @@
#endif #endif
unsigned cpuinfo; unsigned cpuinfo;
unsigned riscv_lg2_vlenb;
static volatile sig_atomic_t got_sigill; static volatile sig_atomic_t got_sigill;
static void sigill_handler(int signo, siginfo_t *si, void *data) static void sigill_handler(int signo, siginfo_t *si, void *data)
@ -34,7 +36,7 @@ static void sigill_handler(int signo, siginfo_t *si, void *data)
/* Called both as constructor and (possibly) via other constructors. */ /* Called both as constructor and (possibly) via other constructors. */
unsigned __attribute__((constructor)) cpuinfo_init(void) unsigned __attribute__((constructor)) cpuinfo_init(void)
{ {
unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND; unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND | CPUINFO_ZVE64X;
unsigned info = cpuinfo; unsigned info = cpuinfo;
if (info) { if (info) {
@ -50,6 +52,10 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
#endif #endif
#if defined(__riscv_arch_test) && defined(__riscv_zicond) #if defined(__riscv_arch_test) && defined(__riscv_zicond)
info |= CPUINFO_ZICOND; info |= CPUINFO_ZICOND;
#endif
#if defined(__riscv_arch_test) && \
(defined(__riscv_vector) || defined(__riscv_zve64x))
info |= CPUINFO_ZVE64X;
#endif #endif
left &= ~info; left &= ~info;
@ -69,11 +75,22 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
#ifdef RISCV_HWPROBE_EXT_ZICOND #ifdef RISCV_HWPROBE_EXT_ZICOND
info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0; info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0;
left &= ~CPUINFO_ZICOND; left &= ~CPUINFO_ZICOND;
#endif
/* For rv64, V is Zve64d, a superset of Zve64x. */
info |= pair.value & RISCV_HWPROBE_IMA_V ? CPUINFO_ZVE64X : 0;
#ifdef RISCV_HWPROBE_EXT_ZVE64X
info |= pair.value & RISCV_HWPROBE_EXT_ZVE64X ? CPUINFO_ZVE64X : 0;
#endif #endif
} }
} }
#endif /* CONFIG_ASM_HWPROBE_H */ #endif /* CONFIG_ASM_HWPROBE_H */
/*
* We only detect support for vectors with hwprobe. All kernels with
* support for vectors in userspace also support the hwprobe syscall.
*/
left &= ~CPUINFO_ZVE64X;
if (left) { if (left) {
struct sigaction sa_old, sa_new; struct sigaction sa_old, sa_new;
@ -113,6 +130,21 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
assert(left == 0); assert(left == 0);
} }
if (info & CPUINFO_ZVE64X) {
/*
* We are guaranteed by RVV-1.0 that VLEN is a power of 2.
* We are guaranteed by Zve64x that VLEN >= 64, and that
* EEW of {8,16,32,64} are supported.
*/
unsigned long vlenb;
/* csrr %0, vlenb */
asm volatile(".insn i 0x73, 0x2, %0, zero, -990" : "=r"(vlenb));
assert(vlenb >= 8);
assert(is_power_of_2(vlenb));
/* Cache VLEN in a convenient form. */
riscv_lg2_vlenb = ctz32(vlenb);
}
info |= CPUINFO_ALWAYS; info |= CPUINFO_ALWAYS;
cpuinfo = info; cpuinfo = info;
return info; return info;