0%

RISCV向量扩展

1. 专有名词(Professional Shortcut)

  • ELEN: Element width,表示向量中一个元素的位宽
  • VLEN: 单个向量寄存器的位宽
  • VL: 当前操作的向量长度(向量中有几个元素)
  • LMUL: vector length multiplier 向量寄存器组,用于将多个向量寄存器合并使用
  • SEW: selected element width

2. 控制与状态寄存器

在V向量扩展中,ISA总共定义了32个通用向量寄存器7个CSR向量寄存器

寄存器名称 描述
vstart 向量起始地址
vxsat 定点数饱和标志
vxrm 定点数舍入模式
vcsr 向量控制和状态寄存器
vl 向量长度,每次向量操作前,都需要程序显式设置vl来确定当前向量操作的长度,对应指令vset{i}vl{i}
vtype 向量数据类型
vlenb 向量寄存器字节宽度(VLEN / 8)
  • vxsat寄存器是一个单比特寄存器,在定点运算中,当结果超出目标数据类型的表示范围时,饱和运算会讲运算结果阶段到数据类型的最大值或最小值而不是溢出,以避免异常值的产生。当执行指令vnclipvsmul时发生了饱和,vxsat寄存器会被置1

3. 向量指令

3.1 配置相关vset{i}vl{i}

以下三条指令用于快速配置vl寄存器和vtype寄存器

  • vsetvli rd, rs1, vtypei

    rd = new vl, rs1 = AVL, vtypei = new vtype setting,该指令将最终vl寄存器设定的值写入rd寄存器中,AVL(application vector length)是目标向量长度,当AVL <= VLMAXrd = AVL,反之rd = VLMAX,同时vtype寄存器根据vtypei参数设置

  • vsetivli rd, uimm, vtypei

    参数含义同上,AVL从立即数中获取

  • vsetvl rd, rs1, rs2

    参数含义同上,vtype设置参数从寄存器中获取

实际运用如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
e8  # SEW = 8b
e16 # SEW = 16b
e32 # SEW = 32b
e64 # SEW = 64b

mf8 # LMUL = 1/8
mf4 # LMUL = 1/4
mf2 # LMUL = 1/2
m1 # LMUL = 1
m2 # LMUL = 2
m4 # LMUL = 4
m8 # LMUL = 8

vsetvli t0, a0, e8, ta, ma # SEW = 8, LMUL = 1
vsetvli t0, a0, e8, m2, ta, ma # SEW = 8, LMUL = 2

3.2 浮点运算

vfcvt指令

该指令用于单精度浮点数有符号/无符号整数之间的转换

1
2
3
4
vfcvt.xu.f.v  vd, vs2, vm // 将浮点数转为无符号整数
vfcvt.x.f.v vd, vs2, vm // 将浮点数转为有符号整数
vfcvt.f.xu.v vd, vs2, vm // 将无符号整数转为浮点数
vfcvt.f.x.v vd, vs2, vm // 将有符号整数转为浮点数

对应intrinsic函数为__riscv_vfcvt_xu_f_v_f32m2(vint32m2_t value, size_t vl),intrinsic函数最后一个部分表示向量返回类型

带舍入的类型转换

根据附录A中的单精度浮点数舍入模式,RVV的intrinsic函数也同样支持自定义舍入模式

  • __riscv_fcvt_x_f_v_i32m2_rm(vfloat32m2_t value, rm_macro, size_t vl)
    • 返回类型:vint32m2_t
    • 目的:单精度浮点类型转为32位整型,rm后缀表示函数中手动指定舍入模式,对应汇编指令中的动态舍入模式
  • __riscv_fcvt_rtz_x_f_v_i32m2(vflaot32m2_t value, size_t vl)
    • 返回类型:vint32m2_t
    • 目的:将单精度浮点数转为32位整型,在函数名中显式指出使用RTZ(round to zero)舍入模式,对应汇编指令中的静态舍入模式

以上两个带舍入模式的fcvt内联函数各自代表F扩展中动态舍入和静态舍入模式,在函数上的差异就是是否在需要参数中指出舍入模式

3.3 整数运算

vzext指令和vsext指令

这两条指令分别用于整数类型的无符号扩展和有符号扩展

1
2
3
4
5
6
vzext.vf2 vd, vs2, vm # 将SEW/2零扩展为SEW位宽
vsext.vf2 vd, vs2, vm # 将SEW/2符号扩展为SEW位宽
vzext.vf4 vd, vs2, vm
vsext.vf4 vd, vs2, vm
vzext.vf8 vd, vs2, vm
vsext.vf8 vd, vs2, vm

对应intrinsic函数有__riscv_vzext_vf4_i32m2(vint8m2_t value, size_t vl)

3.4 定点运算

vnclip指令和vnclipu指令

两条指令都通过将向量元素右移的方式来裁剪舍入定点数的大小,而两条指令的差别就是算数右移和逻辑右移

1
2
3
4
5
6
vnclip.wv vd, vs2, vs1, vm # 算数右移 vd[i] = clip(roundoff_unsigned(vs2[i], vs[i]))
vnclip.wx vd, vs2, rs1, vm
vnclip.wi vd, vs2, rs1, vm
vnclipu.wv vd, vs2, vs1, vm
vnclipu.wx vd, vs2, rs1, vm
vnclipu.wi vd, vs2, uimm, vm

4. 内联函数

rvv intrinsic function是一种由编译器提供的函数借口,该类函数用于将rvv底层复杂的向量汇编指令以更加直观和C适配的方式向上提供接口,其函数命名规则符合规律__riscv_指令_指令后缀_返回类型+LMUL。大多数内联函数都能和向量指令集中的每一条向量一一对应,部分内联函数具有独立含义,不关联于底层向量指令

  • __riscv_vlmul_trunc_v_u8m2_u8fm2(vuint8m2_t value)
    • 返回类型:vuint8fm2_t
    • 目的:裁切vuint8m2_t类型的寄存器组,截取前fm2部分的元素放在新的向量寄存器组并返回
  • __riscv_vluml_ext_v_u8fm2_u8m2(vuint8mf2_t value)
    • 返回类型:vuint8m2_t
    • 目的:扩展vuint8mf2的寄存器组

附录A 单精度浮点舍入模式

在RISCV的F扩展中,有单精度浮点控制和状态寄存器fcsr,该寄存器中5~7共三位的为frm字段,用于控制部分浮点指令动态舍入模式。一个浮点指令的执行要么使用静态舍入模式,要么使用动态舍入模式(从frm字段获取),当一条浮点指令的rm字段设置为DYN(111)时,表示该指令采用动态舍入模式,其舍入方法将从fcsr寄存器的frm字段获取,而rm字段的其他值含义如下

Rounding Mode Mnemonic Meaning
000 RNE 尽量舍入到最近的偶数
001 RTZ 向0舍入
010 RDN 向下舍入,向负无穷
011 RUP 向上舍入,向正无穷
100 RMM 尽量舍入到最近的绝对值最大的数
101 保留
110 保留
111 DYN 动态舍入模式,读取frm字段