diff mbox series

[v3,02/14] util: Add RISC-V vector extension probe in cpuinfo

Message ID 20240904142739.854-3-zhiwei_liu@linux.alibaba.com
State New
Headers show
Series Add support for vector | expand

Commit Message

LIU Zhiwei Sept. 4, 2024, 2:27 p.m. UTC
From: TANG Tiancheng <tangtiancheng.ttc@alibaba-inc.com>

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.

While the compiler doesn't support RISCV_HWPROBE_EXT_ZVE64X,
we use RISCV_HWPROBE_IMA_V instead.

Signed-off-by: TANG Tiancheng <tangtiancheng.ttc@alibaba-inc.com>
Reviewed-by: Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
---
 host/include/riscv/host/cpuinfo.h |  3 +++
 util/cpuinfo-riscv.c              | 26 ++++++++++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)

Comments

Richard Henderson Sept. 5, 2024, 3:34 a.m. UTC | #1
On 9/4/24 07:27, LIU Zhiwei wrote:
> +    if (info & CPUINFO_ZVE64X) {
> +        /*
> +         * Get vlenb for Vector: vsetvli rd, x0, e64.
> +         * VLMAX = LMUL * VLEN / SEW.
> +         * The "vsetvli rd, x0, e64" means "LMUL = 1, SEW = 64, rd = VLMAX",
> +         * so "vlenb = VLMAX * 64 / 8".
> +         */
> +        unsigned long vlmax = 0;
> +        asm volatile(".insn i 0x57, 7, %0, zero, (3 << 3)" : "=r"(vlmax));
> +        if (vlmax) {
> +            riscv_vlenb = vlmax * 8;
> +            assert(riscv_vlen >= 64 && !(riscv_vlen & (riscv_vlen - 1)));
> +        } else {
> +            info &= ~CPUINFO_ZVE64X;
> +        }
> +    }

Surely this does not compile, since the riscv_vlen referenced in the assert does not exist.

That said, I've done some experimentation and I believe there is a further simplification 
to be had in instead saving log2(vlenb).

     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.
          *
          * Cache VLEN in a convenient form.
          */
         unsigned long vlenb;
         asm("csrr %0, vlenb" : "=r"(vlenb));
         riscv_lg2_vlenb = ctz32(vlenb);
     }

I'll talk about how this can be used against the next patch with vsetvl.


r~
LIU Zhiwei Sept. 9, 2024, 7:18 a.m. UTC | #2
On 2024/9/5 11:34, Richard Henderson wrote:
> On 9/4/24 07:27, LIU Zhiwei wrote:
>> +    if (info & CPUINFO_ZVE64X) {
>> +        /*
>> +         * Get vlenb for Vector: vsetvli rd, x0, e64.
>> +         * VLMAX = LMUL * VLEN / SEW.
>> +         * The "vsetvli rd, x0, e64" means "LMUL = 1, SEW = 64, rd = 
>> VLMAX",
>> +         * so "vlenb = VLMAX * 64 / 8".
>> +         */
>> +        unsigned long vlmax = 0;
>> +        asm volatile(".insn i 0x57, 7, %0, zero, (3 << 3)" : 
>> "=r"(vlmax));
>> +        if (vlmax) {
>> +            riscv_vlenb = vlmax * 8;
>> +            assert(riscv_vlen >= 64 && !(riscv_vlen & (riscv_vlen - 
>> 1)));
>> +        } else {
>> +            info &= ~CPUINFO_ZVE64X;
>> +        }
>> +    }
>
> Surely this does not compile, since the riscv_vlen referenced in the 
> assert does not exist.
riscv_vlen is macro about riscv_vlenb. I think you miss it.
>
> That said, I've done some experimentation and I believe there is a 
> further simplification to be had in instead saving log2(vlenb).
>
>     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.
>          *
>          * Cache VLEN in a convenient form.
>          */
>         unsigned long vlenb;
>         asm("csrr %0, vlenb" : "=r"(vlenb));

Should we use the .insn format here? Maybe we are having a compiler 
doesn't support vector.

> riscv_lg2_vlenb = ctz32(vlenb);
>     }
>
OK.

Thanks,
Zhiwei

> I'll talk about how this can be used against the next patch with vsetvl.

>
>
> r~
Richard Henderson Sept. 9, 2024, 3:45 p.m. UTC | #3
On 9/9/24 00:18, LIU Zhiwei wrote:
> 
> On 2024/9/5 11:34, Richard Henderson wrote:
>> On 9/4/24 07:27, LIU Zhiwei wrote:
>>> +    if (info & CPUINFO_ZVE64X) {
>>> +        /*
>>> +         * Get vlenb for Vector: vsetvli rd, x0, e64.
>>> +         * VLMAX = LMUL * VLEN / SEW.
>>> +         * The "vsetvli rd, x0, e64" means "LMUL = 1, SEW = 64, rd = VLMAX",
>>> +         * so "vlenb = VLMAX * 64 / 8".
>>> +         */
>>> +        unsigned long vlmax = 0;
>>> +        asm volatile(".insn i 0x57, 7, %0, zero, (3 << 3)" : "=r"(vlmax));
>>> +        if (vlmax) {
>>> +            riscv_vlenb = vlmax * 8;
>>> +            assert(riscv_vlen >= 64 && !(riscv_vlen & (riscv_vlen - 1)));
>>> +        } else {
>>> +            info &= ~CPUINFO_ZVE64X;
>>> +        }
>>> +    }
>>
>> Surely this does not compile, since the riscv_vlen referenced in the assert does not exist.
> riscv_vlen is macro about riscv_vlenb. I think you miss it.

I did miss the macro.  But there's also no need for it to exist.

>>
>> That said, I've done some experimentation and I believe there is a further 
>> simplification to be had in instead saving log2(vlenb).
>>
>>     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.
>>          *
>>          * Cache VLEN in a convenient form.
>>          */
>>         unsigned long vlenb;
>>         asm("csrr %0, vlenb" : "=r"(vlenb));
> 
> Should we use the .insn format here? Maybe we are having a compiler doesn't support vector.

Neither gcc nor clang requires V be enabled at compile time in order to access the CSR.
It does seem like a mistake, but I'm happy to use it.


r~
LIU Zhiwei Sept. 10, 2024, 2:47 a.m. UTC | #4
On 2024/9/9 23:45, Richard Henderson wrote:
> On 9/9/24 00:18, LIU Zhiwei wrote:
>>
>> On 2024/9/5 11:34, Richard Henderson wrote:
>>> On 9/4/24 07:27, LIU Zhiwei wrote:
>>>> +    if (info & CPUINFO_ZVE64X) {
>>>> +        /*
>>>> +         * Get vlenb for Vector: vsetvli rd, x0, e64.
>>>> +         * VLMAX = LMUL * VLEN / SEW.
>>>> +         * The "vsetvli rd, x0, e64" means "LMUL = 1, SEW = 64, rd 
>>>> = VLMAX",
>>>> +         * so "vlenb = VLMAX * 64 / 8".
>>>> +         */
>>>> +        unsigned long vlmax = 0;
>>>> +        asm volatile(".insn i 0x57, 7, %0, zero, (3 << 3)" : 
>>>> "=r"(vlmax));
>>>> +        if (vlmax) {
>>>> +            riscv_vlenb = vlmax * 8;
>>>> +            assert(riscv_vlen >= 64 && !(riscv_vlen & (riscv_vlen 
>>>> - 1)));
>>>> +        } else {
>>>> +            info &= ~CPUINFO_ZVE64X;
>>>> +        }
>>>> +    }
>>>
>>> Surely this does not compile, since the riscv_vlen referenced in the 
>>> assert does not exist.
>> riscv_vlen is macro about riscv_vlenb. I think you miss it.
>
> I did miss the macro.  But there's also no need for it to exist.
>
>>>
>>> That said, I've done some experimentation and I believe there is a 
>>> further simplification to be had in instead saving log2(vlenb).
>>>
>>>     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.
>>>          *
>>>          * Cache VLEN in a convenient form.
>>>          */
>>>         unsigned long vlenb;
>>>         asm("csrr %0, vlenb" : "=r"(vlenb));
>>
>> Should we use the .insn format here? Maybe we are having a compiler 
>> doesn't support vector.
>
> Neither gcc nor clang requires V be enabled at compile time in order 
> to access the CSR.
> It does seem like a mistake, but I'm happy to use it.

Can we follow you here? 🙂

Zhiwei

>
>
> r~
diff mbox series

Patch

diff --git a/host/include/riscv/host/cpuinfo.h b/host/include/riscv/host/cpuinfo.h
index 2b00660e36..727cb3204b 100644
--- a/host/include/riscv/host/cpuinfo.h
+++ b/host/include/riscv/host/cpuinfo.h
@@ -10,9 +10,12 @@ 
 #define CPUINFO_ZBA             (1u << 1)
 #define CPUINFO_ZBB             (1u << 2)
 #define CPUINFO_ZICOND          (1u << 3)
+#define CPUINFO_ZVE64X          (1u << 4)
 
 /* Initialized with a constructor. */
 extern unsigned cpuinfo;
+extern unsigned riscv_vlenb;
+#define riscv_vlen (riscv_vlenb * 8)
 
 /*
  * We cannot rely on constructor ordering, so other constructors must
diff --git a/util/cpuinfo-riscv.c b/util/cpuinfo-riscv.c
index 497ce12680..05917c42d8 100644
--- a/util/cpuinfo-riscv.c
+++ b/util/cpuinfo-riscv.c
@@ -12,6 +12,7 @@ 
 #endif
 
 unsigned cpuinfo;
+unsigned riscv_vlenb;
 static volatile sig_atomic_t got_sigill;
 
 static void sigill_handler(int signo, siginfo_t *si, void *data)
@@ -33,7 +34,7 @@  static void sigill_handler(int signo, siginfo_t *si, void *data)
 /* Called both as constructor and (possibly) via other constructors. */
 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;
 
     if (info) {
@@ -49,6 +50,9 @@  unsigned __attribute__((constructor)) cpuinfo_init(void)
 #endif
 #if defined(__riscv_arch_test) && defined(__riscv_zicond)
     info |= CPUINFO_ZICOND;
+#endif
+#if defined(__riscv_arch_test) && defined(__riscv_zve64x)
+    info |= CPUINFO_ZVE64X;
 #endif
     left &= ~info;
 
@@ -64,7 +68,8 @@  unsigned __attribute__((constructor)) cpuinfo_init(void)
             && pair.key >= 0) {
             info |= pair.value & RISCV_HWPROBE_EXT_ZBA ? CPUINFO_ZBA : 0;
             info |= pair.value & RISCV_HWPROBE_EXT_ZBB ? CPUINFO_ZBB : 0;
-            left &= ~(CPUINFO_ZBA | CPUINFO_ZBB);
+            info |= pair.value & RISCV_HWPROBE_IMA_V ? CPUINFO_ZVE64X : 0;
+            left &= ~(CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZVE64X);
 #ifdef RISCV_HWPROBE_EXT_ZICOND
             info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0;
             left &= ~CPUINFO_ZICOND;
@@ -112,6 +117,23 @@  unsigned __attribute__((constructor)) cpuinfo_init(void)
         assert(left == 0);
     }
 
+    if (info & CPUINFO_ZVE64X) {
+        /*
+         * Get vlenb for Vector: vsetvli rd, x0, e64.
+         * VLMAX = LMUL * VLEN / SEW.
+         * The "vsetvli rd, x0, e64" means "LMUL = 1, SEW = 64, rd = VLMAX",
+         * so "vlenb = VLMAX * 64 / 8".
+         */
+        unsigned long vlmax = 0;
+        asm volatile(".insn i 0x57, 7, %0, zero, (3 << 3)" : "=r"(vlmax));
+        if (vlmax) {
+            riscv_vlenb = vlmax * 8;
+            assert(riscv_vlen >= 64 && !(riscv_vlen & (riscv_vlen - 1)));
+        } else {
+            info &= ~CPUINFO_ZVE64X;
+        }
+    }
+
     info |= CPUINFO_ALWAYS;
     cpuinfo = info;
     return info;