【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(八)- 向量整数算术指令

 1. 引言

以下是《riscv-v-spec-1.0.pdf》文档的关键内容:
这是一份关于向量扩展的详细技术文档,内容覆盖了向量指令集的多个关键方面,如向量寄存器状态映射、向量指令格式、向量加载和存储操作、向量内存对齐约束、向量内存一致性模型、向量算术指令格式、向量整数和浮点算术指令、向量归约操作、向量掩码指令、向量置换指令、异常处理以及标准向量扩展等。
首先,文档定义了向量元素和向量寄存器状态之间的映射关系,并阐述了向量指令的格式。在此基础上,提出了配置设置指令,如vsetvl、ivsetiv和vlsetvl,用于设定向量长度(VL)和向量对齐长度(AVL)。
接着,文档详细说明了向量加载和存储操作,以及向量内存对齐和一致性模型。这些模型确保了向量操作的高效性和准确性。
然后,文档介绍了向量算术指令格式,包括向量整数、固定点和浮点算术指令。这些指令支持广泛的数学运算,为高性能计算提供了强大的支持。
此外,文档还涉及向量归约操作、掩码指令和置换指令,这些指令增强了向量操作的灵活性和功能性。
最后,文档讨论了异常处理机制,并列举了标准向量扩展指令列表。这些扩展指令为向量处理器提供了丰富的功能集,使其能够适应不同的应用场景和性能需求。
综上所述,这份文档为向量指令集的设计和实现提供了全面的指导和参考,有助于开发者更好地理解和利用向量处理器的能力。

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(一)-向量扩展编程模型-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(二)-向量元素到向量寄存器状态的映射-CSDN博客【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(三)-向量指令格式-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(四)- 配置和设置指令(vsetvli/vsetivli/vsetvl)-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(五)- 向量加载和存储-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(六)- 向量内存一致性模型-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(七)- 向量算术指令格式-CSDN博客

【RISC-V 指令集】RISC-V 向量V扩展指令集介绍(八)- 向量整数算术指令-CSDN博客

11. 向量整数算术指令

提供了一组向量整数算术指令。除非另有说明,否则整数操作会在溢出时环绕。

11.1 向量整数加法和减法

提供了向量整数加法和减法。对于向量-标量形式,还提供了反向减法指令。

# Integer adds.
vadd.vv vd, vs2, vs1, vm    # Vector-vector
vadd.vx vd, vs2, rs1, vm    # vector-scalar
vadd.vi vd, vs2, imm, vm	# vector-immediate

# Integer subtract
vsub.vv vd, vs2, vs1, vm     # Vector-vector
vsub.vx vd, vs2, rs1, vm     # vector-scalar	

# Integer reverse subtract
vrsub.vx vd, vs2, rs1, vm    # vd[i] = x[rs1] - vs2[i]
vrsub.vi vd, vs2, imm, vm    # vd[i] = imm - vs2[i]

注意:可以使用反向减法指令和x0的标量操作数对整数值向量求反。提供了一个汇编伪指令vneg.v vd, vs2 = vrsub.vx vd, vs2, x0。

11.2 扩展向量加法和减法

根据较窄的源操作数在形成双倍宽度和之前是否首先进行符号扩展或零扩展,提供了有符号和无符号两种扩展的加/减指令。

# Widening unsigned integer add/subtract, 2*SEW
vwaddu.vv  vd, vs2, vs1, vm  # vector-vector
vwaddu.vx  vd, vs2, rs1, vm  # vector-scalar
vwsubu.vv  vd, vs2, vs1, vm  # vector-vector
vwsubu.vx  vd, vs2, rs1, vm  # vector-scalar	= SEW +/- SEW
# Widening signed integer add/subtract, 2*SEW =
vwadd.vv  vd, vs2, vs1, vm  # vector-vector
vwadd.vx  vd, vs2, rs1, vm  # vector-scalar
vwsub.vv  vd, vs2, vs1, vm  # vector-vector
vwsub.vx  vd, vs2, rs1, vm  # vector-scalar	SEW +/- SEW
# Widening unsigned integer add/subtract, 2*SEW
vwaddu.wv  vd, vs2, vs1, vm  # vector-vector
vwaddu.wx  vd, vs2, rs1, vm  # vector-scalar
vwsubu.wv  vd, vs2, vs1, vm  # vector-vector
vwsubu.wx  vd, vs2, rs1, vm  # vector-scalar	= 2*SEW +/- SEW
# Widening signed integer add/subtract, 2*SEW =
vwadd.wv  vd, vs2, vs1, vm  # vector-vector
vwadd.wx  vd, vs2, rs1, vm  # vector-scalar
vwsub.wv  vd, vs2, vs1, vm  # vector-vector
vwsub.wx  vd, vs2, rs1, vm  # vector-scalar	2*SEW +/- SEW

可以使用带有x0标量操作数的扩展加法指令将整数值的宽度加倍。提供了汇编伪指令vwcvt.x.x.v vd, vs, vm = vwadd.vx vd, vs, x0, vm和vwcvtu.x.x.v vd, vs, vm = vwaddu.vx vd, vs, x0, vm。

11.3 向量整数扩展指令

向量整数扩展指令将源向量整数操作数(其EEW小于SEW)进行零扩展或符号扩展,以填充目标中的SEW大小元素。源的EEW是SEW的1/2、1/4或1/8,而源的EMUL为(EEW/SEW)*LMUL。目标的EEW等于SEW,EMUL等于LMUL。

vzext.vf2 vd, vs2, vm  # Zero-extend SEW/2 source to SEW destination
vsext.vf2 vd, vs2, vm  # Sign-extend SEW/2 source to SEW destination
vzext.vf4 vd, vs2, vm  # Zero-extend SEW/4 source to SEW destination
vsext.vf4 vd, vs2, vm  # Sign-extend SEW/4 source to SEW destination
vzext.vf8 vd, vs2, vm  # Zero-extend SEW/8 source to SEW destination
vsext.vf8 vd, vs2, vm  # Sign-extend SEW/8 source to SEW destination

如果源EEW不是受支持的宽度,或者源EMUL低于合法的最小LMUL,则该指令编码将被保留。

标准向量加载指令访问与目标寄存器元素大小相同的内存值。一些应用程序代码需要在更宽的元素中对一系列操作数宽度进行操作,例如,从内存中加载一个字节并将其添加到八个字节的元素中。为了避免通过数据类型(字节、字、半字以及有符号/无符号变体)的数量来提供向量加载指令的交叉乘积,我们改为添加明确的扩展指令,如果缺少适当的扩展算术指令,则可以使用这些扩展指令。

11.4 向量整数进位加/借位减指令

为了支持多字整数算术,提供了对进位位进行操作的指令。对于每个操作(加法或减法),都提供了两条指令:一条用于提供结果(SEW宽度),另一条用于生成进位输出(编码为掩码布尔值的单一位)。

进位输入和输出使用掩码寄存器布局表示,如“掩码寄存器布局”部分所述。由于编码限制,进位输入必须来自隐式v0寄存器,但进位输出可以写入任何遵循源/目标重叠限制的向量寄存器。

vadc和vsbc将源操作数与进位或借位相加或相减,并将结果写入向量寄存器vd。这些指令被编码为掩码指令(vm=0),但它们在所有主体元素上运行并写回结果。

对应于未屏蔽版本(vm=1)的编码被保留。

vmadc和vmsbc将源操作数相加或相减,如果屏蔽(vm=0),则选择性地加上进位或减去借位,并将结果写回掩码寄存器vd。如果未屏蔽(vm=1),则没有进位或借位。这些指令即使在屏蔽的情况下也在所有主体元素上运行并写回结果。因为这些指令产生掩码值,所以它们总是以与尾部无关的策略运行。

# Produce sum with carry .
# vd[i] = vs2[i] + vs1[i] + v0.mask[i]
vadc.vvm   vd, vs2, vs1, v0  # Vector-vector
# vd[i] = vs2[i] + x[rs1] + v0.mask[i]
vadc.vxm   vd, vs2, rs1, v0  # Vector-scalar
# vd[i] = vs2[i] + imm + v0.mask[i]
vadc.vim   vd, vs2, imm, v0  # Vector-immediate
# Produce carry out in mask register format
# vd.mask[i] = carry_out(vs2[i] + vs1[i] + v0.mask[i])
vmadc.vvm   vd, vs2, vs1, v0  # Vector-vector
# vd.mask[i] = carry_out(vs2[i] + x[rs1] + v0.mask[i])
vmadc.vxm   vd, vs2, rs1, v0  # Vector-scalar
# vd.mask[i] = carry_out(vs2[i] + imm + v0.mask[i])
vmadc.vim   vd, vs2, imm, v0  # Vector-immediate
# vd.mask[i] = carry_out(vs2[i] + vs1[i])
vmadc.vv    vd, vs2, vs1      # Vector-vector, no carry-in
# vd.mask[i] = carry_out(vs2[i] + x[rs1])
vmadc.vx    vd, vs2, rs1      # Vector-scalar, no carry-in
# vd.mask[i] = carry_out(vs2[i] + imm)
vmadc.vi    vd, vs2, imm      # Vector-immediate, no carry-in

由于实现进位传播需要执行两个输入不变的指令,因此具有破坏性的累加将需要额外的移动才能获得正确的结果。

# Example multi-word arithmetic sequence, accumulating into v4
vmadc.vvm v1, v4, v8, v0  # Get carry into temp register v1
vadc.vvm v4, v4, v8, v0   # Calc new sum
vmmv.m v0, v1             # Move temp carry into v0 for next word

带借位的减法指令vsbc执行与长字算术减法相当的功能。没有带立即数的减法指令。

# Produce difference with borrow.
# vd[i] = vs2[i] - vs1[i] - v0.mask[i]
vsbc.vvm   vd, vs2, vs1, v0  # Vector-vector
# vd[i] = vs2[i] - x[rs1] - v0.mask[i]
vsbc.vxm   vd, vs2, rs1, v0  # Vector-scalar
# Produce borrow out in mask register format
# vd.mask[i] = borrow_out(vs2[i] - vs1[i] - v0.mask[i])
vmsbc.vvm   vd, vs2, vs1, v0  # Vector-vector
# vd.mask[i] = borrow_out(vs2[i] - x[rs1] - v0.mask[i])
vmsbc.vxm   vd, vs2, rs1, v0  # Vector-scalar
# vd.mask[i] = borrow_out(vs2[i] - vs1[i])
vmsbc.vv    vd, vs2, vs1      # Vector-vector, no borrow-in
# vd.mask[i] = borrow_out(vs2[i] - x[rs1])
vmsbc.vx    vd, vs2, rs1      # Vector-scalar, no borrow-in

对于vmsbc,如果差异在截断之前为负,则借位被定义为1。

对于vadc和vsbc,如果目标向量寄存器是v0,则指令编码将被保留。

注意:此约束对应于覆盖掩码寄存器的掩码向量操作的约束。

11.5 位逻辑运算

# Bitwise logical operations.
vand.vv vd, vs2, vs1, vm    # vector-vector
vand.vx vd, vs2, rs1, vm    # vector-scalar
vand.vi vd, vs2, imm, vm	# Vector-immediate

vor.vv vd, vs2, vs1, vm     # Vector-vector
vor.vx vd, vs2, rs1, vm     # vector-scalar
vor.vi vd, vs2, imm, vm	    # vector-immediate

vxor.vv vd, vs2, vs1, vm    # Vector-vector
vxor.vx vd, vs2, rs1, vm    # vector-scalar
vxor.vi vd, vs2, imm, vm    # vector-immediate

注:当立即数为-1时,vxor指令的标量立即数形式提供了按位非操作。这作为汇编伪指令vnot.v vd,vs,vm = vxor.vi vd,vs,-1,vm提供。

11.6 向量移位指令

提供了一套完整的向量移位指令,包括逻辑左移(sll)以及逻辑右移(零扩展srl)和算术右移(符号扩展sra)。要移位的数据位于由vs2指定的向量寄存器组中,并且移位量值可以来自向量寄存器组vs1、标量整数寄存器rs1或零扩展的5位立即数。仅使用移位量值的低lg2(SEW)位来控制移位量。

# Bit shift operations
vsll.vv vd, vs2, vs1, vm    # Vector-vector
vsll.vx vd, vs2, rs1, vm    # vector-scalar
vsll.vi vd, vs2, uimm, vm	# vector-immediate

vs rl.vv vd, vs2, vs1, vm    # Vector-vector
vs rl.vx vd, vs2, rs1, vm    # vector-scalar
vs rl.vi vd, vs2, uimm, vm   # vector-immediate
vs ra.vv vd, vs2, vs1, vm    # Vector-vector
vs ra.vx vd, vs2, rs1, vm    # vector-scalar
vs ra.vi vd, vs2, uimm, vm	 # vector-immediate

11.7 向量右移指令

缩小右移从较宽的操作数中提取一个较小的字段,并具有零扩展(srl)和符号扩展(sra)两种形式。移位量可以来自向量寄存器组、标量x寄存器或零扩展的5位立即数。移位量值的低lg2(2*SEW)位被使用(例如,对于SEW=64位到SEW=32位的缩小操作,使用低6位)。

# Narrowing shift	right logical, SEW = (2*SEW) >>	SEW
vns rl.wv vd, vs2,	vs1, vm   # vector-vector	
vns rl.wx vd, vs2,	rs1, vm   # vector-scalar	
vns rl.wi vd, vs2,	uimm, vm   # vector-immediate	
# Narrowing shift	right arithmetic, SEW = (2*SEW)	>> SEW
vnsra.wv vd, vs2,	vs1, vm   # vector-vector	
vnsra.wx vd, vs2,	rs1, vm   # vector-scalar	
vnsra.wi vd, vs2,	uimm, vm   # vector-immediate	

注:未来的扩展可能会增加对目标宽度为源宽度1/4的缩小版本的支持。

通过使用带有x0标量操作数的缩小整数移位指令,可以将整数值的宽度减半。提供了一个汇编伪指令vncvt.x.x.w vd,vs,vm = vnsrl.wx vd,vs,x0,vm。

11.8 整数比较指令

以下整数比较指令在比较结果为真时将1写入目标掩码寄存器元素,否则写入0。目标掩码向量始终保存在单个向量寄存器中,元素的布局如“掩码寄存器布局”部分所述。目标掩码向量寄存器可能与源向量掩码寄存器(v0)相同。

# Set if equal
vmseq.vv vd, vs2, vs1, vm  # Vector-vector
vmseq.vx vd, vs2, rs1, vm  # vector-scalar
vmseq.vi vd, vs2, imm, vm  # vector-immediate
# Set if not equal
vmsne.vv vd, vs2, vs1, vm  # Vector-vector
vmsne.vx vd, vs2, rs1, vm  # vector-scalar
vmsne.vi vd, vs2, imm, vm  # vector-immediate
# Set if less than, unsigned
vmsltu.vv vd, vs2, vs1, vm  # Vector-vector
vmsltu.vx vd, vs2, rs1, vm  # Vector-scalar
# Set if less than, signed
vmslt.vv vd, vs2, vs1, vm  # Vector-vector
vmslt.vx vd, vs2, rs1, vm  # vector-scalar
# Set if less than or equal, unsigned
vmsleu.vv vd, vs2, vs1, vm   # Vector-vector
vmsleu.vx vd, vs2, rs1, vm   # vector-scalar
vmsleu.vi vd, vs2, imm, vm   # Vector-immediate
# Set if less than or equal, signed
vmsle.vv vd, vs2, vs1, vm  # Vector-vector
vmsle.vx vd, vs2, rs1, vm  # vector-scalar
vmsle.vi vd, vs2, imm, vm  # vector-immediate
# Set if greater than, unsigned
vmsgtu.vx vd, vs2, rs1, vm   # Vector-scalar
vmsgtu.vi vd, vs2, imm, vm   # Vector-immediate
# Set if greater than, signed
vmsgt.vx vd, vs2, rs1, vm    # Vector-scalar
vmsgt.vi vd, vs2, imm, vm    # Vector-immediate
# Following two instructions are not provided directly
# Set if greater than or equal, unsigned
# vmsgeu.vx vd, vs2, rs1, vm    # Vector-scalar
# Set if greater than or equal, signed
# vmsge.vx vd, vs2, rs1, vm    # Vector-scalar

下表显示了所有比较如何在原生机器代码中实现。

Comparison      Assembler Mapping            Assembler Pseudoinstruction
va < vb         vmslt{u}.vv vd, va, vb, vm
va <= vb        vmsle{u}.vv vd, va, vb, vm
va > vb         vmslt{u}.vv vd, vb, va, vm    vmsgt{u}.vv vd, va, vb, vm
va >= vb        vmsle{u}.vv vd, vb, va, vm    vmsge{u}.vv vd, va, vb, vm
va < x          vmslt{u}.vx vd, va, x, vm
va <= x         vmsle{u}.vx vd, va, x, vm
va > x          vmsgt{u}.vx vd, va, x, vm
va >= x         see below
va < i          vmsle{u}.vi vd, va, i-1, vm   vmslt{u}.vi vd, va, i, vm
va <= i         vmsle{u}.vi vd, va, i, vm
va > i          vmsgt{u}.vi vd, va, i, vm
va >= i         vmsgt{u}.vi vd, va, i-1, vm   vmsge{u}.vi vd, va, i, vm
va, vb vector register groups
x      scalar integer register
i      immediate	

注意:没有提供vmslt{u}.vi的立即数形式,因为可以通过将立即数值减1并使用vmsle{u}.vi变体来替代。vmsle.vi的范围是-16到15,这使得vmslt.vi的有效范围为-15到16。vmsleu.vi的范围是0到15,从而使得vmsltu.vi的有效范围为1到16(注意,vmsltu.vi的立即数为0时是没有用的,因为它总是返回假)。

由于5位向量立即数总是进行符号扩展,因此当设置simm5立即数的高位时,vmsleu.vi还支持2^(SEW-16)到2^(SEW-1)范围内的无符号立即数值,允许相应的vmsltu.vi与2^(SEW-15)到2^SEW范围内的无符号立即数进行比较。请注意,vmsltu.vi的立即数为2^SEW时是无用的,因为它总是返回真。

类似地,没有提供vmsge{u}.vi,而是使用立即数减1的vmsgt{u}.vi来实现比较。这产生的有效vmsge.vi范围是-15到16,而有效的vmsgeu.vi范围是1到16(注意,vmsgeu.vi的立即数为0时是无用的,因为它总是返回真)。

注意:提供寄存器标量和立即数的vmsgt形式,是为了允许单个比较指令提供正确的掩码值极性,而无需使用额外的掩码逻辑指令。

为了减少编码空间,没有直接提供vmsge{u}.vx形式,因此对于va = x的情况需要特殊处理。

注意:vmsge{u}.vx可能以非正交方式在未使用的vmslt{u}的OPIVI变体下进行编码。然而,这些将是OPIVI中唯一使用标量x寄存器的指令。或者,可以使用另外两个funct6编码,但这些编码的操作数格式(写入掩码寄存器)将与同一组8个funct6编码中的其他编码不同。当前的建议是省略这些指令,并在需要时按如下所述进行合成。

当知道不会使x中的表示形式下溢时,可以通过将x的值减小1并使用vmsgt{u}.vx指令来合成vmsge{u}.vx操作。

Sequences to synthesize `vmsge{u}.vx` instruction
va >= x,  x > minimum
addi t0, x, -1; vmsgt{u}.vx vd, va, t0, vm

上述序列通常将是最有效的实现方式,但是在x的范围未知的情况下,可以提供汇编伪指令。

unmasked va >= x
pseudoinstruction: vmsge{u}.vx vd, va, x
expansion: vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd
masked va >= x, vd != v0
pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t
expansion: vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0
masked va >= x, vd == v0
pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t, vt
expansion: vmslt{u}.vx vt, va, x;  vmandn.mm vd, vd, vt
masked va >= x, any vd
pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t, vt
expansion: vmslt{u}.vx vt, va, x;  vmandn.mm vt, v0, vt;  vmandn.mm vd, vd, v0;  vmor.mm vd, vt, vd
The vt argument to the pseudoinstruction must name a temporary vector register that is
not same as vd and which will be clobbered by the pseudoinstruction

例如,在不受掩码干扰的策略下,有效地在掩码中进行与比较。

# (a < b)	&& (b	< c) in	two instructions when mask-undisturbed
vmslt.vv	v0,	va,	vb	# All body elements written
vmslt.vv	v0,	vb,	vc,	v0.t  # Only update at set mask

比较写掩码寄存器,因此总是在尾部不可知策略下操作。

11.9 向量整数的最小值和最大值指令

支持有符号和无符号整数的最小值和最大值指令。

# Unsigned minimum
vminu.vv vd, vs2, vs1, vm    # Vector-vector
vminu.vx vd, vs2, rs1, vm    # vector-scalar
# Signed minimum
vmin.vv vd, vs2, vs1, vm    # Vector-vector
vmin.vx vd, vs2, rs1, vm    # vector-scalar
# Unsigned maximum
vmaxu.vv vd, vs2, vs1, vm    # Vector-vector
vmaxu.vx vd, vs2, rs1, vm    # vector-scalar
# Signed maximum
vmax.vv vd, vs2, vs1, vm    # Vector-vector
vmax.vx vd, vs2, rs1, vm	# vector-scalar

11.10 向量单宽度乘法指令

单宽度乘法指令执行SEW位SEW位乘法以生成2SEW位乘积,然后在SEW位宽的目标位置返回乘积的一半。mul版本将乘积的低字写入目标寄存器,而mulh版本将乘积的高字写入目标寄存器。

# Signed multiply, returning low bits of product
vmul.vv vd, vs2, vs1, vm   # Vector-vector
vmul.vx vd, vs2, rs1, vm   # vector-scalar
# Signed multiply, returning high bits of product
vmulh.vv vd, vs2, vs1, vm   # Vector-vector
vmulh.vx vd, vs2, rs1, vm   # vector-scalar
# Unsigned multiply, returning high bits of product
vmulhu.vv vd, vs2, vs1, vm   # Vector-vector
vmulhu.vx vd, vs2, rs1, vm   # vector-scalar
# Signed(vs2)-Unsigned multiply, returning high bits of product
vmulhsu.vv vd, vs2, vs1, vm   # Vector-vector
vmulhsu.vx vd, vs2, rs1, vm   # vector-scalar

注意:没有vmulhus.vx操作码来返回无符号向量*有符号标量乘积的高半部分。可以将标量扩展为向量,然后使用vmulhsu.vv。

当前的vmulh*操作码执行简单的分数乘法,但没有选项来对结果进行缩放、四舍五入和/或饱和处理。未来可能的扩展可以考虑vmulh、vmulhu、vmulhsu的变体,这些变体在丢弃乘积的低半部分时使用vx rm舍入模式。在这些情况下,不可能发生溢出。

11.11 向量除法和取余指令

除法和取余指令等同于RISC-V标准标量整数乘/除指令,对于极端输入,结果相同。

# Unsigned divide.
vdivu.vv vd, vs2, vs1, vm    # Vector-vector
vdivu.vx vd, vs2, rs1, vm    # vector-scalar
# Signed divide
vdiv.vv vd, vs2, vs1, vm    # Vector-vector
vdiv.vx vd, vs2, rs1, vm    # vector-scalar
# Unsigned remainder
vremu.vv vd, vs2, vs1, vm    # Vector-vector
vremu.vx vd, vs2, rs1, vm    # vector-scalar
# Signed remainder
vrem.vv vd, vs2, vs1, vm    # Vector-vector
vrem.vx vd, vs2, rs1, vm	# vector-scalar

注意:关于是否包含整数除法和取余功能的决定是有争议的。支持这一决定的论点是,如果没有标准指令,软件将不得不选择某种算法来执行该操作,而这可能在某些微体系结构上表现不佳,与其他体系相比会处于劣势。

没有执行“标量除以向量”操作的指令。

11.12 向量扩展整数乘法指令

扩展整数乘法指令从SEW位SEW位乘法中返回完整的2SEW位乘积。

# Widening signed-integer multiply
vwmul.vv  vd, vs2, vs1, vm # vector-vector
vwmul.vx  vd, vs2, rs1, vm # vector-scalar
# Widening unsigned-integer multiply
vwmulu.vv vd, vs2, vs1, vm # vector-vector
vwmulu.vx vd, vs2, rs1, vm # vector-scalar
# Widening signed(vs2)-unsigned integer multiply
vwmulsu.vv vd, vs2, vs1, vm # vector-vector
vwmulsu.vx vd, vs2, rs1, vm # vector-scalar

11.13 向量整数乘加指令

整数乘法-加法指令具有破坏性,并提供两种形式,一种是覆盖加数或被减数的(vmacc, vnmsac),另一种是覆盖第一个乘数的(vmadd, vnmsub)。

乘积的低半部分与第三个操作数相加或相减。

注意:sac应读作“从累加器中减去”。操作码vnmsac是为了与(不幸的是,这有点违反直觉)浮点fnmsub指令定义相匹配。vnmsub操作码也类似。

# Integer multiply-add, overwrite addend
vmacc.vv vd, vs1, vs2, vm    # vd[i] = +(vs1[i] * vs2[i]) + vd[i]
vmacc.vx vd, rs1, vs2, vm    # vd[i] = +(x[rs1] * vs2[i]) + vd[i]
# Integer multiply-sub, overwrite minuend
vnmsac.vv vd, vs1, vs2, vm    # vd[i] = -(vs1[i] * vs2[i]) + vd[i]
vnmsac.vx vd, rs1, vs2, vm    # vd[i] = -(x[rs1] * vs2[i]) + vd[i]
# Integer multiply-add, overwrite multiplicand
vmadd.vv vd, vs1, vs2, vm    # vd[i] = (vs1[i] * vd[i]) + vs2[i]
vmadd.vx vd, rs1, vs2, vm    # vd[i] = (x[rs1] * vd[i]) + vs2[i]
# Integer multiply-sub, overwrite multiplicand
vnmsub.vv vd, vs1, vs2, vm    # vd[i] = -(vs1[i] * vd[i]) + vs2[i]
vnmsub.vx vd, rs1, vs2, vm    # vd[i] = -(x[rs1] * vd[i]) + vs2[i]

11.14 向量扩展整数乘法-加法指令

扩展整数乘法-加法指令将一个SEW位SEW位乘法的完整2SEW位乘积加到一个2SEW位的值上,并生成一个2SEW位的结果。支持有符号和无符号乘法操作数的所有组合。

# Widening unsigned-integer multiply-add, overwrite addend
vwmaccu.vv vd, vs1, vs2, vm    # vd[i] = +(vs1[i] * vs2[i]) + vd[i]
vwmaccu.vx vd, rs1, vs2, vm    # vd[i] = +(x[rs1] * vs2[i]) + vd[i]
# Widening signed-integer multiply-add, overwrite addend
vwmacc.vv vd, vs1, vs2, vm    # vd[i] = +(vs1[i] * vs2[i]) + vd[i]
vwmacc.vx vd, rs1, vs2, vm    # vd[i] = +(x[rs1] * vs2[i]) + vd[i]
# Widening signed-unsigned-integer multiply-add, overwrite addend
vwmaccsu.vv vd, vs1, vs2, vm  # vd[i] = +(signed(vs1[i]) * unsigned(vs2[i])) + vd[i]
vwmaccsu.vx vd, rs1, vs2, vm  # vd[i] = +(signed(x[rs1]) * unsigned(vs2[i])) + vd[i]
# Widening unsigned-signed-integer multiply-add, overwrite addend
vwmaccus.vx vd, rs1, vs2, vm  # vd[i] = +(unsigned(x[rs1]) * signed(vs2[i])) + vd[i]

11.15 向量整数合并指令

向量整数合并指令基于掩码组合两个源操作数。与常规算术指令不同,合并操作对所有主体元素(即从vstart到当前向量长度vl的元素集)进行操作。

vmerge指令被编码为带掩码的指令(vm=0)。这些指令按以下方式组合两个源。在掩码值为零的元素处,将第一个操作数复制到目标元素,否则将第二个操作数复制到目标元素。第一个操作数始终是由vs2指定的向量寄存器组。第二个操作数是由vs1指定的向量寄存器组,或由rs1指定的标量x寄存器,或是一个5位符号扩展的立即数。

vmerge.vvm vd, vs2, vs1, v0  # vd[i] = v0.mask[i] ? vs1[i] : vs2[i]
vmerge.vxm vd, vs2, rs1, v0  # vd[i] = v0.mask[i] ? x[rs1] : vs2[i]
vmerge.vim vd, vs2, imm, v0  # vd[i] = v0.mask[i] ? imm     : vs2[i]

11.6 向量整数移动指令

向量整数移动指令将一个源操作数复制到向量寄存器组。vmv.v.v变体复制一个向量寄存器组,而vmv.v.x和vmv.v.i变体将标量寄存器或立即数分散到目标向量寄存器组的所有活动元素中。这些指令被编码为未屏蔽的指令(vm=1)。第一个操作数指定器(vs2)必须包含v0,vs2中的任何其他向量寄存器号都是保留的。

vmv.v.v	vd,	vs1	#	vd[i]	=	vs1[i]
vmv.v.x	vd,	rs1	#	vd[i]	=	x[rs1]
vmv.v.i	vd,	imm	#	vd[i]	=	imm

注意

可以使用序列vmv.v.i vd, 0; vmerge.vim vd, vd, 1, v0将掩码值加宽为SEW宽度元素。

向量整数移动指令与向量合并指令共享编码,但vm=1且vs2=v0。

形式为vmv.v.v vd, vd的指令,它使主体元素保持不变,可以用来表示该寄存器接下来将与等于SEW的EEW一起使用。

注意

根据EEW在内部重新组织数据的实现可以根据SEW对内部表示进行混洗。不在内部重新组织数据的实现可以动态地省略此指令,并将其视为NOP。

vmv.v.v vd.vd指令不是RISC-V HINT,因为在某些实现上,尾部不可知的设置可能会导致体系结构状态发生变化。

你可能感兴趣的:(RISC-V,指令集分析,risc-v,人工智能,机器学习)