rvv 相关配置参数说明
前言/引言
今天面试中遇到了一些关于rvv的参数相关的问题,本身比较一知半解,所以还是挺尴尬的,说自己会写rvv。所以这里对于常用的一些参数进行记录。
基础配置参数
按照在写rvvkernel中遇到的来说明,主要有一下几个:
- vl
- 向量长度,通常是通过
__riscv_vsetvl_e32m1来自动获取当前一个向量的元素数
- 向量长度,通常是通过
- vlen
- 和硬件相关的单个向量寄存器宽度,128、256、512
- elen
- 硬件支持的最大元素宽度:32、64等
- sew
- 根据dtype来确定,fp32: sew=32 ;fp16:sew=16
- lmul
- 通过
mX的x来确定具体使用的向量寄存器数量
- 通过
vlmax
- 根据前面三者计算得到:$vlmax = (vlen*lmul)/ seq$,
RVV内在函数核心标记总览
| 标记字母 | 在函数名中的位置 | 全称/含义 | 功能描述 | 示例 |
|---|---|---|---|---|
v |
前缀 | Vector | 标识这是一个向量操作。 | vadd, vle32 |
l / s |
v之后 |
Load / Store | 表示内存操作是加载(读内存)还是存储(写内存)。 | vle32 (加载), vse32 (存储) |
s |
l和e之间 |
Strided | 表示使用显式步长的非连续内存访问。 | **vlse32**, vsse32 |
x |
l和e之间 |
Indexed | 表示使用向量寄存器中的索引进行散状(Gather)或散开(Scatter)访问。 | vlxei32, vsxei32 |
e |
l/s之后 |
Element width | 指示内存中单个数据元素的宽度(位数)。紧随其后的数字即为宽度。 | vle**32** (32位元素) |
m |
e{width}之后 |
Machine register LMUL | 指示操作使用的向量寄存器组(LMUL)。数字为分组因子。 | vadd.**v**v**i32m1** (使用LMUL=1) |
u / f |
e{width}之后 |
Unsigned / Float | 指示操作数的数据类型是无符号整数或浮点数。 | vle32**u** (无符号加载), vle32**f** (浮点加载) |
v / x / i |
运算操作名之后 | Operand Source | 指示操作数的来源:v(向量), x(标量), i(立即数)。 |
vadd.**vv** (向量+向量), vadd.**vx** (向量+标量), vadd.**vi** (向量+立即数) |
m |
操作数来源之后 | Mask | 表示这是一个掩码操作,使用v0作为谓词掩码。 |
vadd.vv **m** (掩码加法) |
t |
指令后缀 | Tied Operand | 表示目的操作数与第一个源操作数是同一个寄存器(融合操作数)。常用于归约等操作。 | vredsum.vs **t** |
高级应用
1. 内存操作三剑客
这三种加载指令覆盖了所有主流的内存访问模式,是编程的核心:
vle32: 连续访问。效率最高,是基础。vlse32: 固定步长访问。用于处理矩阵行列、结构体数组。vlxei32: 索引访问(Gather)。功能最强大也最灵活,允许通过一个索引向量从任意地址收集数据,适合处理完全不规则的数据(如哈希表、稀疏矩阵的非零元)。
2. 掩码操作 (m)
这是实现条件向量化和循环尾部处理的关键。例如,vmadd.vv表示 “在掩码为1的通道上,执行乘法累加”,这可以避免对数组边界外或不符合条件的元素进行操作。
3. 归约与融合操作数 (t)
像 vredsum.vs 这样的归约操作,会将一个向量“压缩”成一个标量。标记 t 表示其目的标量寄存器与一个源向量寄存器是同一个物理寄存器(被“绑定”了),这种设计优化了寄存器文件的压力。