From 0bee1b615e43c6ba62b59227bbb473b3ba45abb9 Mon Sep 17 00:00:00 2001 From: Felix-Gong Date: Tue, 13 Oct 2026 09:21:00 +0000 Subject: [PATCH] CRC32C RISC-V: pick clmul or vclmul by size when both are available PR3332 sent every Zbc+Zvbc CPU to the vclmul path. After #3571 rewrote it, vclmul beats clmul from ~256 B up (1.5x-7.5x) but costs more below that, where vector setup dominates. A fixed order to either path is wrong for these CPUs. Select by size in the dispatcher: clmul under 256 B, vclmul from 256 B on. CPUs with only Zbc or only Zvbc keep their current path, and Extend() is untouched. k3 (X100, VLEN=256, 20-round median): 256 B clmul 1534 vclmul 2155 1 MiB clmul 1555 vclmul 11702 (MB/s) Signed-off-by: Xiaofei Gong Signed-off-by: YuanSheng --- src/butil/crc32c.cc | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/butil/crc32c.cc b/src/butil/crc32c.cc index ac81c7f63e..4715709307 100644 --- a/src/butil/crc32c.cc +++ b/src/butil/crc32c.cc @@ -814,6 +814,15 @@ static bool isSSE42() { typedef uint32_t (*Function)(uint32_t, const char*, size_t); +#if defined(__riscv) && (__riscv_xlen == 64) && defined(__riscv_zbc) && defined(__riscv_zvbc) +// Both Zbc and Zvbc: scalar is cheaper for small inputs, the vector fold +// wins from ~256 B on. +static constexpr size_t kRiscvVclmulThresholdBytes = 256; +static uint32_t RiscvExtend(uint32_t crc, const char* buf, size_t size) { + return (size >= kRiscvVclmulThresholdBytes ? rv_crc32c_vclmul : rv_crc32c_clmul)(crc, buf, size); +} +#endif + static inline Function Choose_Extend() { #ifdef __SSE4_2__ if (isSSE42()) { @@ -821,12 +830,25 @@ static inline Function Choose_Extend() { } #endif #if defined(__riscv) && (__riscv_xlen == 64) && (defined(__riscv_zbc) || defined(__riscv_zvbc)) -#if defined(__riscv_zvbc) +#if defined(__riscv_zbc) && defined(__riscv_zvbc) + { + static const bool has_zbc = is_zbc(); + static const bool has_zvbc = is_zvbc(); + if (has_zbc && has_zvbc) { + return (Function)RiscvExtend; + } + if (has_zvbc) { + return (Function)rv_crc32c_vclmul; + } + if (has_zbc) { + return (Function)rv_crc32c_clmul; + } + } +#elif defined(__riscv_zvbc) if (is_zvbc()) { return (Function)rv_crc32c_vclmul; } -#endif -#if defined(__riscv_zbc) +#elif defined(__riscv_zbc) if (is_zbc()) { return (Function)rv_crc32c_clmul; }