矢量ALU指令(VALU)对64个线程中的每一个线程的数据执行算术或逻辑操作,并将结果写回VGPR、SGPR或EXEC掩码。
参数插值是一种混合VALU和LDS指令,在数据共享章节中描述。
6.1. 微码编码
大多数VALU指令有两种编码格式:使用64位指令的VOP3,以及三种32位编码之一(提供受限功能集)。少数指令仅以VOP3编码格式提供。唯一不能使用VOP3格式的指令是参数插值指令。
当指令有两种微码格式时,由用户决定使用哪一种。建议尽可能使用32位编码。
微码编码如下所示:
-
VOP2:用于具有两个输入和一个矢量目的地的指令。产生进位输出的指令隐式地将进位输出写入VCC寄存器。
-
VOP1:用于无输入或单输入和一个目的地的指令。
-
VOPC:用于比较指令。
-
VINTRP:用于参数插值指令。
-
VOP3:用于最多三个输入、输入修饰符(取负和绝对值)和输出修饰符的指令。VOP3有两种形式:一种使用标量目的地字段(仅用于div_scale、整数加减);这被称为VOP3b。所有其他指令使用通用形式,称为VOP3a。
-
VOP3P:用于使用"打包数学"的指令:它们对打包到每个操作数高低16位中的一对输入值执行操作;两个16位结果作为两个打包值写入单个VGPR。
任何32位微码格式都可以使用32位字面常量,但VOP3不能。
6.2. 操作数
所有VALU指令至少需要一个输入操作数(除了V_NOP和V_CLREXCP)。操作数的数据大小在指令名称中明确定义。例如,V_MAD_F32对32位浮点数据进行操作。
6.2.1. 指令输入
VALU指令可以使用以下任何源作为输入,受以下列出的限制约束:
-
VGPR
-
SGPR
-
内联常量 - 由特定VSRC值选择的常量
-
字面常量 - 指令流中的32位值
-
LDS直接数据读取
-
M0
-
EXEC掩码
限制:
-
每条指令最多只能读取一个SGPR,但其值可以用于多个操作数
-
最多只能使用一个字面常量,且仅当未使用SGPR或M0作为源时
-
只有SRC0可以使用LDS_DIRECT
常量的特殊情况 :
VALU "ADDC"、"SUBB"和CNDMASK都隐式使用SGPR值(VCC),因此这些指令不能使用额外的SGPR或字面常量。
使用VOP3格式并且使用浮点输入的指令可以选择对任何输入操作数应用绝对值(ABS字段)或取负(NEG字段)。
字面常量扩展到64位 :
字面常量是32位的,但它们可以用作通常需要64位数据的源:
-
64位浮点:低32位用零填充
-
64位无符号整数:零扩展到64位
-
64位有符号整数:符号扩展到64位
6.2.2. 指令输出
VALU指令通常将其结果写入微码字VDST字段中指定的VGPR。仅当EXEC掩码中的关联位设置为1时,线程才会写入结果。
所有V_CMPX指令将其比较结果(每个线程一位)写入SGPR(或VCC)和EXEC掩码。
产生进位输出的指令(整数加减)在VOP2格式下将其结果写入VCC,在VOP3格式下写入任意的SGPR对。
当使用VOP3格式时,具有浮点结果的指令可以应用输出修饰符(OMOD字段),将结果乘以:0.5、1.0、2.0或4.0。可选地,结果可以钳位(CLAMP字段)到范围[0.0,+1.0]。
输出修饰符仅适用于浮点结果,对整数或位结果被忽略。输出修饰符与输出非规格化数不兼容:如果启用输出非规格化数,则忽略输出修饰符。如果禁用输出非规格化数,则应用输出修饰符并将非规格化数刷新为零。输出修饰符不符合IEEE标准:-0被刷新为+0。如果IEEE模式位设置为1,则忽略输出修饰符。
操作数表(部分):
| 值 | 名称 | 描述 |
|---|---|---|
| 0-101 | SGPR 0..101 | 标量通用寄存器 |
| 102 | FLATSCR_LO | Flat Scratch[31:0] |
| 103 | FLATSCR_HI | Flat Scratch[63:32] |
| 104 | XNACK_MASK_LO | |
| 105 | XNACK_MASK_HI | |
| 106 | VCC_LO | vcc[31:0] |
| 107 | VCC_HI | vcc[63:32] |
| 108-123 | TTMP0..TTMP15 | 陷阱处理程序临时寄存器(特权) |
| 124 | M0 | |
| 125 | 保留 | |
| 126 | EXEC_LO | exec[31:0] |
| 127 | EXEC_HI | exec[63:32] |
| 128 | 0 | 零值 |
| 129-192 | int 1..64 | 整数内联常量 |
| 193-208 | int -1..-16 | 负整数内联常量 |
| 235-238 | 内存孔径定义 | SHARED_BASE等 |
| 240 | 0.5 | 浮点内联常量 |
| 241 | -0.5 | |
| 242 | 1.0 | |
| ... | ... | 其他浮点常量 |
| 248 | 1/(2*PI) | 1/(2π)常量 |
| 249 | SDWA | 子字寻址(仅对Source-0有效) |
| 250 | DPP | 16通道DPP(仅对Source-0有效) |
| 251 | VCCZ | { zeros, VCCZ } |
| 252 | EXECZ | { zeros, EXECZ } |
| 253 | SCC | { zeros, SCC } |
| 254 | LDS direct | 使用LDS直接读取提供32位值 |
| 255 | Literal constant | 指令流中的32位常量 |
| 256-511 | VGPR 0..255 | 矢量通用寄存器 |
6.2.3. 超出范围的GPR
当源VGPR超出范围时,指令使用VGPR0的值作为输入。
当目的地GPR超出范围时,指令执行但不写入结果。
6.3. 指令集
以下表格按微码编码列出了完整的VALU指令集,除了后面部分列出的VOP3P指令。
VALU指令集摘要:
-
VOP3:V_MAD_LEGACY_F32、V_ADD_F64、V_MAD_{F16,I16,U16,F32}等
-
VOP2:V_ADD_{F16,F32,U16,U32}、V_SUB_{F16,F32,U16,U32}等
-
VOP1:V_NOP、V_MOV_B32、V_CVT_{...}等
-
比较指令:V_CMP_{I16,I32,...}、V_CMPX_{...}、V_CMP_CLASS等
比较指令表:
-
V_CMP:比较16/32/64位整数或浮点数,写入VCC
-
V_CMPX:比较并写入VCC和exec掩码
-
V_CMP_CLASS:测试浮点数类型(NaN、无穷大、规格化数、非规格化数、零)
6.4. 非规格化数和舍入模式
着色器程序对应用的舍入模式以及非规格化数输入和结果的处理有显式控制。使用S_SETREG指令设置MODE寄存器;它有单独的位来控制单精度和双精度浮点数的行为。
舍入模式:
- 0=最近偶数;1=正无穷大;2=负无穷大;3=向零舍入
非规格化模式:
-
0=刷新输入和输出非规格化数
-
1=允许输入非规格化数,刷新输出非规格化数
-
2=刷新输入非规格化数,允许输出非规格化数
-
3=允许输入和输出非规格化数
6.5. ALU钳位位使用
在GCN Vega架构中,VALU指令中"钳位"位的含义已更改。对于V_CMP指令,将钳位位设置为1表示如果发生浮点异常,比较会产生信号。对于整数操作,它将结果钳位到最大和最小可表示值。对于浮点操作,它将结果钳位到范围:[0.0,1.0]。
6.6. VGPR索引
VGPR索引允许存储在M0寄存器中的值作为索引,用于VALU指令中的源或目的地寄存器。
6.6.1. 索引指令
-
S_SET_GPR_IDX_OFF:禁用VGPR索引模式
-
S_SET_GPR_IDX_ON:启用VGPR索引,并从SGPR设置索引值和模式
-
S_SET_GPR_IDX_IDX:设置VGPR索引值
-
S_SET_GPR_IDX_MODE:更改存储在M0[15:12]中的VGPR索引模式
索引由MODE寄存器中的gpr_idx_en位启用和禁用。启用时,使用M0中的两个字段确定索引值及其应用对象:
-
M0[7:0]:保存无符号索引值,添加到选定的源或目的地VGPR地址
-
M0[15:12]:保存四位掩码,指示索引应用于哪个源或目的地
索引仅适用于VGPR源和目的地,不适用于内联常量或SGPR。索引尝试寻址超出范围的VGPR是非法的。
6.7. 打包数学
Vega增加了对打包数学的支持,它在一个双字内对两个16位值执行操作,就好像它们是独立的线程。例如,V0=V1+V2的打包加法实际上是两个独立的加法:将每个双字的低16位相加并将结果存储在V0的低16位,以及将高半部分相加。
打包数学使用以下指令和微码格式"VOP3P"。该格式为低和高操作数添加了op_sel和neg字段,并移除了ABS和OMOD。
打包数学操作码 :
V_PK_MAD_I16、V_PK_MUL_LO_U16、V_PK_ADD_I16、V_PK_SUB_I16、V_PK_FMA_F16等。
V_MAD_MIX_*不是打包数学,但会对16位和32位输入的混合执行单个MAD操作。它们在此列出是因为它们使用VOP3P编码。