所有矢量内部函数都要求 AI 引擎矢量寄存器内存在操作数。下表显示了一组矢量寄存器以及将较小的寄存器组合为大型寄存器的方式。
128 位 | 256 位 | 512 位 | 1024 位 | |
---|---|---|---|---|
vrl0 | wr0 | xa | ya | 不适用 |
vrh0 | ||||
vrl1 | wr1 | |||
vrh1 | ||||
vrl2 | wr2 | xb | yd (msbs) | |
vrh2 | ||||
vrl3 | wr3 | |||
vrh3 | ||||
vcl0 | wc0 | xc | 不适用 | 不适用 |
vch0 | ||||
vcl1 | wc1 | |||
vch1 | ||||
vdl0 | wd0 | xd | 不适用 | yd (lsbs) |
vdh0 | ||||
vdl1 | wd1 | |||
vdh1 |
底层基本硬件寄存器位宽为 128 位,并以字母 v 作为前缀。两个 v 寄存器可组合构成一个 256 位寄存器,以 w 作为前缀。wr、wc 和 wd 寄存器可成对组合构成 512 位寄存器(xa、xb、xc 和 xd)。xa 和 xb 构成位宽为 1024 位的 ya 寄存器,而 xd 和 xb 则构成位宽为 1024 位的 yd 寄存器。这意味着在 ya 与 yd 寄存器之间共享 xb 寄存器。xb 包含最高有效位 (MSB) 供 ya 和 yd 寄存器使用。
矢量寄存器名称可搭配 chess_storage
指令来使用,以强制将矢量数据存储在特定矢量寄存器内。例如:
v8int32 chess_storage(wr0) bufA;
v8int32 chess_storage(WR) bufB;
如果在 chess_storage
指令中使用大写,就表示寄存器文件(例如,任意 4 个 wr 寄存器),而指令中使用小写就表示仅选中特定寄存器(例如,前述代码示例中的 wr0)。
矢量寄存器是宝贵资源。如果代码生成期间,编译器可用的矢量寄存器出现不足,那么它会生成代码,将寄存器内容溢出到本地寄存器内,并按需读回这些内容。这会耗用额外的时钟周期。
在内核微码中会显示内核执行期间所使用的矢量寄存器的名称,以供矢量加载/存储和其它基于矢量的指令使用。在 Vitis IDE 的反汇编视图中可获取此微码。如需了解有关 Vitis IDE 用法的更多详细信息,请参阅 使用 Vitis IDE 和报告。
许多内部函数仅接受特定矢量数据类型,但有时并不需要来自该矢量的所有值。例如,某些内部函数仅接受 512 位矢量。如果内核代码数据大小较小,那么有一种技巧很有用,即使用 concat()
内部函数将此较小的数据与未定义的矢量(矢量的类型已定义,但未初始化)串联。
例如,lmul8
内部函数仅接受 v16int32
或 v32int32
矢量用于其 xbuff
参数。内部函数原型为:
v8acc80 lmul8 ( v16int32 xbuff,
int xstart,
unsigned int xoffsets,
v8int32 zbuff,
int zstart,
unsigned int zoffsets
)
xbuff
参数期望的是 16 元素矢量 (v16int32)。在以下示例中,有一个 8 元素矢量 (v8int32
) rva。concat()
内部函数用于将其升级至 16 元素矢量。串联后,16 元素矢量的下半部分包含 rva 的内容。由于 16 元素矢量的上半部分与未定义的 v8int32
矢量串联,因此未初始化。
int32 a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
v8int32 rva = *((v8int32*)a);
acc = lmul8(concat(rva,undef_v8int32()),0,0x76543210,rvb,0,0x76543210);
如需了解有关基于矢量的内部函数的工作原理的更多信息,请参阅 矢量寄存器通道置换。