RISC-V RVV intrinsic指令优化指南

引言

RISC-V的Vector扩展使得RISC-V处理器能够执行向量计算, 目前的编译器已经提供了一部分自动向量化的能力, 但如果要更加充分地发挥处理器向量化计算的能力, 还是需要由程序员理解计算的过程, 灵活调用intrinsic指令进行优化。然而, RISC-V 的Vector intrinsic指令细分下来有上万条, 具体该如何去调用?如何避免一不小心因为函数名很类似而调用错误的intrinsic指令?

基本指南

可以参考这两个已经Ratified的标准, 来使用intrinsic指令。

另外有一个网页可以比较方便地查找intrinsic指令的定义:dzaima.github.io/intrinsics-viewer

LSP

现代的编辑器一般都会带有LSP(Language Server Protocol)的支持, 可以实现语法补全, 跳转, 代码检查, 格式化等功能。

clangd 是一个LSP服务器, 在VSCode, Neovim等编辑器中都有支持, 但是它对于这些RVV的intrinsic指令的支持并不是很好。

相关讨论

相关的issue:clangd/2143

Clangd doesn’t understand the RISC-V vector intrinsics generated by #pragma clang riscv intrinsic vector in <riscv_vector.h>. The __riscv_vsetvl_xxx defines work, but operations such as __riscv_vadd_vv_u64m4() aren’t detected properly and are flagged as errors.

从这里可以看到, <riscv_vector.h> 中虽然通过 #pragma clang riscv intrinsic vector 生成了intrinsic指令, 使得编译器能够识别, 但是clangd无法识别。

从目前的讨论结果来看, 主要还是等上游更新支持。

临时的解决方案

从表面的现象来说, clangd无法识别intrinsic指令, 只需要额外添加一些intrinsic指令的声明就能够解决这个问题。

因此我写了一个脚本, 根据rvv-intrinsic-doc 中所列出的intrinsic指令, 自动生成相应的头文件, 然后在clangd的配置文件中添加这些头文件即可。

相关的实现参考仓库:qiujiandong/rvv-intrinsic

只需要在项目的compile_commands.json同级的目录中添加一个.clangd的配置文件, 并添加如下类似的配置:

1
2
3
4
5
6
CompileFlags:
Add:
[
-include /path/to/repo/rvv_intrinsic/rvv_intrinsic.h,
-I /path/to/repo/rvv-intrinsic/rvv_intrinsic,
]

clangd 就能够正确识别intrinsic指令了。

Demo:

demo