LLVM 中 RISC-V SIMD(以 RVV 为主)代码分析与使用指南
1. 先说结论
在 LLVM/Clang 里,RISC-V 的“SIMD”主要是 V 扩展(RVV, Vector Extension)。 实现是分层的:
- Clang 前端:定义/生成
riscv_vector.h与 builtin,做语义检查; - LLVM IR/中端:使用 scalable vector、RVV intrinsic、VP intrinsic;
- LLVM RISC-V 后端:DAG/GISel 降低、RVV pseudo 指令选择、
vsetvli插入优化; - 测试:
llvm/test/CodeGen/RISCV/rvv下大量.ll/.mir用例。
另外,RISC-V 也有 P extension(packed-SIMD) 路线,但当前主线 SIMD 能力和生态重点是 RVV。
2. 相关代码“在哪”
2.1 Clang 前端(intrinsics/builtin/头文件)
-
RVV 指令描述(TableGen 源)
clang/include/clang/Basic/riscv_vector.tdclang/include/clang/Basic/riscv_vector_common.tdclang/include/clang/Basic/riscv_sifive_vector.tdclang/include/clang/Basic/riscv_andes_vector.td -
目标特性与 builtin 注册
clang/lib/Basic/Targets/RISCV.cpp -
RVV builtin 语义检查
clang/lib/Sema/SemaRISCV.cppclang/include/clang/Sema/SemaRISCV.h -
RVV builtin 到 LLVM IR 的 CodeGen
clang/lib/CodeGen/TargetBuiltins/RISCV.cpp -
RVV 类型/签名工具
clang/include/clang/Support/RISCVVIntrinsicUtils.hclang/lib/Support/RISCVVIntrinsicUtils.cpp -
TableGen 生成器(把
riscv_vector.td变成各类.inc)clang/utils/TableGen/RISCVVEmitter.cpp
2.2 生成产物(构建目录)
-
生成的 RVV builtin
.inc(示例)build-debug/tools/clang/include/clang/Basic/riscv_vector_builtins.incbuild-debug/tools/clang/include/clang/Basic/riscv_vector_builtin_sema.incbuild-debug/tools/clang/include/clang/Basic/riscv_vector_builtin_cg.inc -
生成的头文件(示例)
build-debug/tools/clang/lib/Headers/riscv_vector.hbuild-debug/lib/clang/21/include/riscv_vector.h
2.3 LLVM RISC-V 后端(核心)
-
后端主目录
llvm/lib/Target/RISCV -
RVV lowering/合法化/向量核心逻辑
llvm/lib/Target/RISCV/RISCVISelLowering.cpp -
指令选择相关模式
llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.tdllvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.tdllvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.tdllvm/lib/Target/RISCV/RISCVInstrInfoV.td -
vsetvli插入与分析/优化llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cppllvm/lib/Target/RISCV/RISCVVSETVLIInfoAnalysis.cppllvm/lib/Target/RISCV/RISCVVLOptimizer.cpp -
RVV 相关优化/修复 pass(示例)
llvm/lib/Target/RISCV/RISCVVectorPeephole.cppllvm/lib/Target/RISCV/RISCVVectorMaskDAGMutation.cppllvm/lib/Target/RISCV/RISCVVMV0Elimination.cpp
2.4 文档与测试
-
官方后端机制文档
llvm/docs/RISCV/RISCVVectorExtension.rst -
RISC-V 总体使用文档(含扩展支持状态)
llvm/docs/RISCVUsage.rst -
RVV CodeGen 回归测试
llvm/test/CodeGen/RISCV/rvv/
3. 代码链路(从 riscv_vector.td 到最终汇编)
- 在
riscv_vector.td定义 intrinsic/builtin 规则; RISCVVEmitter.cpp生成 builtin/语义/codegen 的.inc;- Clang 在
SemaRISCV.cpp检查类型、特性、策略参数; - Clang 在
TargetBuiltins/RISCV.cpp发射 LLVM IR intrinsic; - LLVM 后端在
RISCVISelLowering.cpp降低为 VL 节点/伪指令; RISCVInsertVSETVLI根据数据流插入最少必要的vsetvli;- 最终由 AsmPrinter 输出 RVV 指令。
4. 关键 commit(里程碑与近期演进)
下面是从仓库 git log 中筛出的高相关提交(按时间与主题整理)。
4.1 起步阶段(基础设施)
5baef6353e88(2020-11-30)[RISCV] Initial infrastructure for code generation of the RISC-V V-extensiona6805a0e02c9(2020-12-11) 定义vadd/vsub/vrsubintrinsic 并 lowering 到 V 指令c1d6d461aa77(2020-12-15) 定义vle/vseintrinsicd6a0560bf258(2021-03-05) Clang 增加 RVV 专用 TableGen backend(RISCVVEmitter)95c0125f2bc6(2021-02-25) Clang 增加vsetvl/vsetvlmaxintrinsic
4.2 RVV 1.0 与前端生态扩展
0649dfebbab7(2021-11-04) RVV 1.0 命名更新09058654f68d(2023-12-18) Vector Crypto 扩展去 experimental239127d731e6(2024-08-31) LLVM IR 支持 RISC-V vector tuple type0727e7a8a9fd(2025-10-18) 后端支持Zvfbfacodegen8c5a0f74a12d(2025-12-24) 支持Zvfofp8minllvm intrinsic 与 codegen
4.3 近期(2026)优化/新扩展
67601a43b57a(2026-01-12) 增加RISCVVSETVLIInfoAnalysis79a1b80af856(2026-01-12) 按兼容vtype/vl优先调度 RVV 指令0d11f68a8aa2(2026-02-03)VLOptimizer提前到 ISel 后运行972e73b812cb/e99259334168(2026-02-09)Zvabdlowering 与 codegen5c1426737479(2026-02-14) Clang 增加Zvabdintrinsicsa59b4fca866a(2026-02-26)RISCVVLOptimizer使用elementsDependOnVL改造
4.4 与 P-extension SIMD 的一个提示
118f64ad20d9(2026-02-25) 移除-riscv-enable-p-ext-simd-codegen。 说明“SIMD”在 RISC-V 路线上需要区分 RVV 与 P-extension,两者在 LLVM 里的策略和成熟度不同。
5. 如何使用(开发者视角)
5.1 直接写 RVV C intrinsic
最常见方式:#include <riscv_vector.h>。
编译示例(RV64 + GCV):
clang --target=riscv64 -march=rv64gcv -mabi=lp64d -O2 test.c -S -o test.s
如果要开具体向量子扩展(示例):
clang --target=riscv64 -march=rv64gcv_zvbb_zvbc -mabi=lp64d -O2 test.c -S -o test.s
5.2 让自动向量化走 RVV
clang --target=riscv64 -march=rv64gcv -mabi=lp64d -O3 test.c -S -o test.s
可结合 remark 看向量化情况:
clang --target=riscv64 -march=rv64gcv -mabi=lp64d -O3 \
-Rpass=loop-vectorize -Rpass-missed=loop-vectorize test.c -c
5.3 固定向量长度相关参数(后端文档里常见)
llvm/docs/RISCV/RISCVVectorExtension.rst 中提到可用:
-mrvv-vector-bits=zvl
或:
-mllvm -riscv-v-vector-bits-max=<VLEN>
用于需要固定/已知 VLEN 场景(例如某些 fixed-length vector 降低路径)。
5.4 验证是否生成 RVV 指令
clang --target=riscv64 -march=rv64gcv -mabi=lp64d -O2 test.c -S -o - | rg "vsetvli|vle|vse|vadd|vm"
如果有 vsetvli 与 v* 指令,通常说明已走 RVV 路径。
6. C++ 示例:从 intrinsic 到后端 SIMD
下面是一个最小链路示例(vle -> vadd -> vse):
// rvv_add.cpp
#include <cstddef>
#include <cstdint>
#include <riscv_vector.h>
extern "C" void add_i32_rvv(const int32_t *a, const int32_t *b, int32_t *c, size_t n) {
size_t i = 0;
while (i < n) {
size_t vl = __riscv_vsetvl_e32m1(n - i);
vint32m1_t va = __riscv_vle32_v_i32m1(a + i, vl);
vint32m1_t vb = __riscv_vle32_v_i32m1(b + i, vl);
vint32m1_t vc = __riscv_vadd_vv_i32m1(va, vb, vl);
__riscv_vse32_v_i32m1(c + i, vc, vl);
i += vl;
}
}
观察链路的命令:
# 1) 前端到 LLVM IR(会看到 llvm.riscv.* intrinsic)
clang --target=riscv64 -march=rv64gcv -mabi=lp64d -O2 -S -emit-llvm rvv_add.cpp -o rvv_add.ll
rg "llvm.riscv|vsetvl|vadd|vle|vse" rvv_add.ll
# 2) LLVM IR 到 RISC-V 汇编
llc -mtriple=riscv64 -mattr=+v rvv_add.ll -o rvv_add.s
# 3) 确认后端确实生成 RVV SIMD 指令
rg "vsetvli|vle32\\.v|vadd\\.vv|vse32\\.v" rvv_add.s
你会看到:
- C++ intrinsic 调用;
- IR 中
llvm.riscv.*(目标相关 intrinsic); - 后端输出 RVV 指令(含
vsetvli)。
7. 想移植一个 intrinsic,可参考哪些 commit
下面是“新增/移植 intrinsic”最有参考价值的一组提交(从简单到复杂):
95c0125f2bc6(2021-02-25)[Clang][RISCV] Add rvv vsetvl and vsetvlmax intrinsic functions.适合看最基础 builtin/intrinsic 接入。be947aded019(2021-03-17)[RISCV][Clang] Add RVV vle/vse intrinsic functions.典型 load/store intrinsic。66c05609e0d5(2021-03-29)[RISCV][Clang] Add some RVV Integer intrinsic functions.典型算术 intrinsic。593bf9b4ded3(2021-05-25)[Clang][RISCV] Implement vlseg and vlsegff.分段 load/store(更复杂签名)。239127d731e6(2024-08-31)[llvm][RISCV] Support RISCV vector tuple type in llvm IRtuple 类型链路关键点。0727e7a8a9fd(2025-10-18)[RISCV] Support Zvfbfa codegen子扩展 codegen 接入案例。8c5a0f74a12d(2025-12-24)[RISCV][llvm] Support Zvfofp8min llvm intrinsics and codegen新子扩展 + LLVM intrinsic + codegen 联动。5c1426737479(2026-02-14)[Clang][RISCV] Add Zvabd intrinsics较新的前端 intrinsic 扩展案例。972e73b812cb/e99259334168(2026-02-09)Zvabd的后端 lowering 与 codegen 对应提交。 适合配合上面的 clang 提交一起看“前后端打通”。
7.1 移植时建议按这个顺序改
- 在
clang/include/clang/Basic/riscv_vector*.td增加定义; - 确认生成
.inc与riscv_vector.h(TableGen/构建产物); - 必要时补
SemaRISCV.cpp的特性与参数检查; - 在 LLVM 后端
.td/.cpp增加 intrinsic/lowering/pattern; - 补 clang/llvm 双侧测试(
clang/test+llvm/test/CodeGen/RISCV/rvv)。
8. 常用定位命令(维护/二次分析)
# 找 RVV 后端实现
rg -n "RVV|VSETVLI|VVL|VPseudo|Scalable" llvm/lib/Target/RISCV
# 找 Clang RVV 前端入口
rg -n "riscv_vector|RVV|__builtin_rvv" clang/lib clang/include/clang
# 看 RVV 测试
ls llvm/test/CodeGen/RISCV/rvv | head
# 看最近 RVV 提交
git log --oneline -- llvm/lib/Target/RISCV clang/include/clang/Basic/riscv_vector.td | rg -i "rvv|vector|vsetvli|zv"
9. 一个实用阅读顺序
- 先读
llvm/docs/RISCV/RISCVVectorExtension.rst(架构全景); - 再看
clang/include/clang/Basic/riscv_vector.td(intrinsic 定义); - 跟到
clang/lib/Sema/SemaRISCV.cpp和clang/lib/CodeGen/TargetBuiltins/RISCV.cpp; - 最后看
RISCVISelLowering.cpp、RISCVInstrInfoVVLPatterns.td、RISCVInsertVSETVLI.cpp。