Technical Guide & Advice for Porting Open-Source Software to RISC-V
Date: August 2026
Scope: Actionable advice, best practices, and anti-patterns derived from analyzing 147 open-source project status reports (reports directory).
Executive Summary
Porting software to RISC-V (riscv64) effectively requires navigating key architectural and ecosystem challenges: dynamic vector length (VLEN) variance, compiler ISA flag compatibility, runtime feature detection, PyPI wheel packaging, and native CI test gating.
This guide outlines actionable technical suggestions for open-source maintainers and contributors to ensure successful, production-grade RISC-V ports.
1. Build System & Compilation Infrastructure
A. Avoid Hardcoding Fixed Vector Lengths (march flags)
- The Issue: Hardcoding static vector bit-width flags like
-march=rv64gcv_zvl128bcauses compilation errors or runtime segfaults on hardware with different vector lengths (e.g.VLEN=256on SpacemiT X100/K1 chips). - Evidence: In vLLM, hardcoded
zvl128bcaused hard crashes onVLEN=256chips until PR #39478 introduced dynamic CMake VLEN parameterization. - Best Practice: Use generic compiler vector flags (
-march=rv64gcv) and parameterize vector lengths in CMake/Meson (-DVLLM_RVV_VLEN=<N>), allowing runtime or build-time VLEN configuration.
B. Handle -march=native Gracefully in JIT Compilers
- The Issue: Pass-through flags like
-march=nativesent to GCC/g++ on RISC-V can cause compiler crashes because GCC requires explicit target ISA strings (starting withrv64...). - Evidence: In PyTorch Inductor,
-march=nativecaused hard crashes until PR #167071 and PR #184297 added explicit RISC-V target handling (cpp.march). - Best Practice: Add explicit architecture checks for
riscv64in JIT code generators to pass valid target strings (e.g.rv64gcorrv64gcv).
C. Automatically Guard Non-Existent x86/ARM Dependencies
- The Issue: Build systems frequently attempt to compile x86-only submodules (e.g., FBGEMM, NNPACK, psimd, MKL) on RISC-V, resulting in build failures.
- Evidence: In PyTorch Dependencies.cmake, building on RISC-V required manually specifying
-DUSE_CUDA=OFF -DUSE_MKLDNN=OFF -DUSE_FBGEMM=OFF -DUSE_NNPACK=OFF. - Best Practice: Update project CMake/Meson allowlists so that when
CMAKE_SYSTEM_PROCESSORisriscv64, architecture-specific submodules are automatically disabled without requiring manual user flags.
2. Runtime Hardware Feature Detection
A. Use Kernel Hardware Probe Syscalls (sys_riscv_hwprobe)
- The Issue: Scrape-parsing
/proc/cpuinfofor ISA strings is brittle because vendor Linux kernels and QEMU user-mode emulators often omit VLEN hint flags (likezvl128b), causing silent fallbacks to slow scalar code. - Evidence: On Sophgo SG2044 hardware, vLLM degraded to scalar performance because
/proc/cpuinfolackedzvl128bflags, requiring a C++ fallback helper in PR #43179. - Best Practice: Use the Linux 6.4+
sys_riscv_hwprobe()syscall or thecpuinfolibrary API (src/riscv/) to query hardware vector and ISA capabilities dynamically at runtime.
B. Validate FP16/BF16 Vector Extension Support
- The Issue: Unconditionally compiling with
-march=rv64gcv_zvfhwithout verifying CPU runtime support forZvfh(half-precision vector) orZvfbfmin(BFloat16 vector) causes illegal instruction exceptions (SIGILL) or numerical corruption. - Evidence: In XNNPACK, unconditionally enabling
Zvfhflags without acpuinfo_has_riscv_zvfh()check resulted in over 100 FP16 test failures (Issue #9886). - Best Practice: Gate FP16 (
Zvfh) and BF16 (Zvfbfmin) vector code paths behind runtime ISA extension checks before dispatching vector kernels.
3. RVV 1.0 Vectorization & Kernel Design
A. Support Scalable Vector Types (vfloat32m1_t) Over Fixed Structs
- The Issue: C++ SIMD abstractions (like PyTorch’s
Vectorized<T>) often assume fixed 128-bit or 256-bit register layouts (Vectorized::size()), blocking vectorization on scalable vector architectures. - Evidence: In PyTorch, core RVV ATen vectorization (PR #175746) stalled because template assumptions conflicted with scalable vector memory copies.
- Best Practice: Decouple SIMD vector register wrappers from fixed memory sizes. Use RVV C intrinsics with dynamic LMUL mappings (
vfloat32m1_t,vfloat32m2_t) or C++ RVV intrinsic libraries like Google Highway.
B. Clamp Inputs for Transcendental & Polynomial Vector Kernels
- The Issue: Polynomial approximations for
exp(),tanh(), orerf()using RVV vector fused multiply-accumulate (vfmacc) can overflow or produceNaNon large negative inputs via-inf * 0.0 = NaN. - Evidence: In vLLM, unclamped
FP32Vec16::exp()producedNaNscores in attention softmax until PR #40428 added input clamping to[-87.33, 88.72]. - Best Practice: Always clamp input ranges in math function vector kernels before evaluating polynomial series.
4. CI/CD Infrastructure & Testing
A. Adopt Free Bare-Metal CI Runners (RISE Runners)
- The Issue: Relying solely on QEMU user-mode emulation in CI is slow, lacks real RVV 1.0 hardware validation, and often fails on binfmt setup in containerized runners.
- Evidence: In PyTorch, in-tree native build PR #182278 failed due to QEMU container permission issues.
- Best Practice: Integrate free native RISC-V runners provided by the RISE RISC-V Runners program (Scaleway EM-RV1 bare-metal servers, GitHub label
ubuntu-24.04-riscv) into.github/workflows/.
B. Use Out-of-Tree CI Relays to Reduce Maintainer Burden
- The Issue: Mainstream maintainers hesitate to add non-blocking RISC-V CI jobs in-tree due to runner maintenance overhead.
- Evidence: The RISE project established
riseproject-dev/pytorch-ciusing GitHub workflow dispatch relays (PyTorch PR #181739) to test pull requests on native hardware without burdening core maintainers. - Best Practice: Use label-triggered workflow relays (
ciflow/riscv64) so community runners can run test suites independently.
5. Packaging & Governance
A. Publish manylinux_2_31_riscv64 PyPI Wheels
- The Issue: End users experience heavy friction when
pip installfails to find binary wheels, triggering long C++/Rust compilation cycles. - Best Practice: Add
manylinux_2_31_riscv64wheel build stages usingcibuildwheelor submit packages to the RISE Wheel Builder.
B. Designate Named RISC-V Maintainers (CODEOWNERS)
- The Issue: Pull requests stall for months when maintainers have no explicit SLA or assignment for RISC-V code paths.
- Best Practice: Add a
RISC-Vsection toCODEOWNERSand assign named community reviewers (e.g. from RISE member companies) to review and approve architecture-specific PRs promptly.
Summary Checklist for Project Maintainers
| Domain | Best Practice Checklist | Primary Benefit |
|---|---|---|
| Build System | ✅ Parameterize VLEN; avoid fixed -march=zvl128b. |
Prevents segfaults on 256-bit vector hardware. |
| Compiler Flags | ✅ Handle RISC-V target strings in JIT compilers instead of -march=native. |
Fixes GCC/Clang JIT compilation crashes. |
| Feature Detection | ✅ Use sys_riscv_hwprobe or cpuinfo API for runtime ISA detection. |
Avoids false-negative scalar fallbacks. |
| Vector Kernels | ✅ Clamp inputs to math functions (exp(), tanh()). |
Prevents NaN output corruption in attention layers. |
| CI Testing | ✅ Integrate RISE RISC-V Runners (ubuntu-24.04-riscv). |
Enables fast, native bare-metal PR testing. |
| Packaging | ✅ Publish manylinux_2_31_riscv64 PyPI wheels via cibuildwheel. |
Eliminates user build-from-source friction. |