训练营学员

傲来操作系统训练营报告

RVV C Intrinsic 配置教程

张宇轩 发布于 # 2024 年第一期

一、环境配置

目前riscv-gnu-toolchain中对RVV扩展已经非常成熟,但并没有提供合适的RVV C Intrinsics接口供开发人员使用。 自 RVV 1.0发布以来,intriniscs的相关支持在 LLVM 上比较活跃,相关接口包含在头文件 riscv_vector.h 内。

参考博客后,采用 LLVM Clang + GCC Newlib Toolchain 的方式进行配合,前者做编译,后者提供libc等基础库。

  • Ubuntu 22.04 (jammy):Ubuntu 20.04 (focal) 也可以,其他OS需要自行编译 riscv64 工具链
  • LLVM-14:从 apt源 下载即可
  • riscv64-unknown-elf工具链:从 GitHub 上拉去最新的Nightly release即可

首先安装 LLVM-14:

注意 LLVM 15及以后采用内部规则解析,作为前端riscv_vector.h的一系列声明就没了,因此本篇报告使用的是 LLVM-14。

wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14

检查安装是否成功:

$ clang-14 --version
Ubuntu clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

然后下载riscv64-unknown-elf工具链;这里特别注意 riscv64-elfubuntu-版本号(我使用的是22.04,所以选ubuntu-22.04)、gcc 几个关键词。

wget https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2024.04.12/riscv64-elf-ubuntu-22.04-gcc-nightly-2024.04.12-nightly.tar.gz

下载完毕后解压到指定路径,一般选用/opt/riscv/usr/local/riscv,这里以/usr/local/riscv为例:

sudo tar -xvf riscv64-elf-ubuntu-22.04-gcc-nightly-2024.04.12-nightly.tar.gz -C /usr/local/

然后将/usr/local/riscv/bin添加到当前Shell的环境变量中:

echo export PATH="/usr/local/riscv/bin:$PATH" >> ~/.bashrc
source ~/.bashrc

检查riscv64-unknown-elf工具链:

$ riscv64-unknown-elf-gcc --version
riscv64-unknown-elf-gcc () 13.2.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

二、Hello World

一个简单的向量加法vadd.c如下所示:

// Reference: https://pages.dogdog.run/toolchain/riscv_vector_extension.html

#include <riscv_vector.h>
#include <stdio.h>

int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int y[10] = {0, 9, 8, 7, 6, 5, 4, 3, 2, 1};
int z[10];

void vec_add_rvv(int* dst, int* lhs, int* rhs, size_t avl) {
    vint32m2_t vlhs, vrhs, vres;
    for (size_t vl; (vl = vsetvl_e32m2(avl));
         avl -= vl, lhs += vl, rhs += vl, dst += vl) {
        vlhs = vle32_v_i32m2(lhs, vl);
        vrhs = vle32_v_i32m2(rhs, vl);
        vres = vadd_vv_i32m2(vlhs, vrhs, vl);
        vse32_v_i32m2(dst, vres, vl);
    }
}

int main(int argc, char const* argv[]) {
    vec_add_rvv(z, x, y, 10);
    for (int i = 0; i < 10; ++i) printf("%d ", z[i]);
    printf("\n");
    return 0;
}

可以看到VSCode的Intellisense是能很好支持的:

vscode_support

编译:

clang-14 --target=riscv64-unknown-elf -march=rv64gv --gcc-toolchain=/usr/local/riscv -O2 -g ./vadd.c -o ./vadd
  • 使用 --target 指定编译器后端为riscv64-unknown-elf
  • 通过 -march=rv64gv 指定目标指令集为 RV64G(通用) 和 RV64V(向量扩展)
  • --gcc-toolchain设置为刚刚解压的riscv64-unknown-elf工具链目录

通过QEMU运行:

qemu-riscv64 -cpu rv64,v=true,vlen=128 ./vadd
  • -cpu 指定目标处理器架构,选用rv64,同时令v=true表示启用V扩展,并设置vlen=128

一次完整执行过程如下:

$ clang-14 --target=riscv64-unknown-elf -march=rv64gv --gcc-toolchain=/usr/local/riscv -O2 -g ./vadd.c -o ./vadd
$ qemu-riscv64 -cpu rv64,v=true,vlen=128 ./vadd
vector version is not specified, use the default value v1.0
1 11 11 11 11 11 11 11 11 1

可以参考rvv-intrinsic-doc的示例代码,需要注意不再需要包含__riscv前缀

三、参考

你需要熟悉这两份参考手册:

同时也可以了解 RiVEC Benchmark,是体系结构中最早应用于gem5上的RVV Benchmark