[Bugfix][CPU][RISC-V] Fix VLEN detection for RVV attention path (#47532)

Signed-off-by: liutong <liutong@iscas.ac.cn> Co-authored-by: Claude <noreply@anthropic.com>

LiuTong committed Jul 6, 2026 at 13:58 UTC 16f81109357041f844aebfd4cb35e95600e2dda9
3 files changed +26 -18
cmake/cpu_extension.cmake
+11 -1
@@ -178,7 +178,10 @@ elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64")
178 # Override with -DVLLM_RVV_VLEN=128 or -DVLLM_RVV_VLEN=256 for RVV.
179 if(NOT DEFINED VLLM_RVV_VLEN)
180 # Auto-detect: find the largest zvl<N>b in /proc/cpuinfo isa line.
181 - if(EXISTS /proc/cpuinfo)
181 + # Skip when cross-compiling — /proc/cpuinfo describes the build host.
182 + if(CMAKE_CROSSCOMPILING)
183 + message(STATUS "Cross-compiling: skipping VLEN auto-detection from /proc/cpuinfo")
184 + elseif(EXISTS /proc/cpuinfo)
185 file(READ /proc/cpuinfo _cpuinfo)
186 set(_best 0)
187 foreach(_n IN ITEMS 128 256 512 1024)
@@ -186,6 +189,13 @@ elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64")
189 set(_best ${_n})
190 endif()
191 endforeach()
192 + # Only VLEN=128 and VLEN=256 are supported by the RVV kernels.
193 + if(_best GREATER 256)
194 + message(WARNING
195 + "Detected VLEN=${_best} but only 128/256 are supported; "
196 + "clamping to 256")
197 + set(_best 256)
198 + endif()
199 if(_best GREATER 0)
200 set(VLLM_RVV_VLEN ${_best})
201 endif()
csrc/cpu/cpu_attn.cpp
+2 -1
@@ -13,7 +13,8 @@ static inline cpu_attention::Fp8KVCacheDataType parse_fp8_kv_dtype(
13
14 bool cpu_attn_has_isa(const std::string& isa) {
15 if (isa == "rvv") {
16 -#if defined(__riscv) && defined(__riscv_v_min_vlen) && __riscv_v_min_vlen == 128
16 +#if defined(__riscv) && defined(__riscv_v_min_vlen) && \
17 + (__riscv_v_min_vlen == 128 || __riscv_v_min_vlen == 256)
18 return true;
19 #else
20 return false;
vllm/v1/attention/backends/cpu_attn.py
+13 -16
@@ -437,27 +437,24 @@ def _riscv_supports_rvv() -> bool:
437 The RVV path is compiled whenever __riscv_v_min_vlen is defined, so
438 we check that at least one supported zvl<N>b is advertised.
439 """
440 - try:
441 - with open("/proc/cpuinfo") as f:
442 - cpuinfo = f.read()
443 - except OSError:
444 - return False
445 - # If VLEN >= 512 is detected, the RVV kernel was not compiled.
446 - if any(f"zvl{n}b" in cpuinfo for n in (512, 1024)):
447 - return False
448 -
449 - # zvl128b or zvl256b explicitly advertised -> RVV kernel available.
450 - if any(f"zvl{n}b" in cpuinfo for n in (128, 256)):
451 - return True
452 -
453 - # No zvl<N>b flag at all (e.g. some hardware reports zve* without
454 - # a VLEN hint). Delegate to the C++ compile-time check instead.
440 + # The C++ compile-time check is the ground truth: it knows which
441 + # VLEN the binary was actually compiled for. The cpuinfo check
442 + # below is only a fast-path shortcut.
443 try:
444 import torch
445
458 - return torch.ops._C.cpu_attn_has_isa("rvv")
446 + if torch.ops._C.cpu_attn_has_isa("rvv"):
447 + return True
448 except Exception:
449 + pass
450 +
451 + # Fallback: check /proc/cpuinfo for zvl128b/zvl256b.
452 + try:
453 + with open("/proc/cpuinfo") as f:
454 + cpuinfo = f.read()
455 + except OSError:
456 return False
457 + return any(f"zvl{n}b" in cpuinfo for n in (128, 256))
458
459
460 def _get_attn_isa(