14

查看 AVX2 内在文档,收集了加载指令,例如VPGATHERDD

__m128i _mm_i32gather_epi32 (int const * base, __m128i index, const int scale);

从文档中我不清楚的是计算的加载地址是 元素地址还是字节地址,即 element 的加载地址i

load_addr = base + index[i] * scale;               // (1) element addressing ?

或者:

load_addr = (char *)base + index[i] * scale;       // (2) byte addressing ?

英特尔文档看来,它可能是 (2),但考虑到收集负载的最小元素大小是 32 位,这没有多大意义 - 为什么要从未对齐的地址加载(即使用 scale < 4 ) ?

4

3 回答 3

11

收集说明没有任何对齐要求。所以不允许字节寻址就太严格了。

另一个原因是一致性。使用 SIB 寻址,我们显然有字节地址:

MOV eax, [rcx + rdx * 2]

由于VPGATHERDD只是该MOV指令的矢量化变体,因此我们不应期望 VSIB 寻址有任何不同:

VPGATHERDD ymm0, [rcx + ymm2 * 2], ymm3

至于字节寻址的实际用途,我们可以有一个 24 位彩色图像,其中每个像素都是 3 字节对齐的。我们可以使用单个 VPGATHERDD 指令加载 8 个像素,但前提是 VSIB 中的“缩放”字段为“1”并VPGATHERDD使用字节寻址。

于 2013-04-24T15:13:17.857 回答
5

从此处可用的英特尔AVX 编程参考文档中的描述来看,收集指令似乎使用字节寻址。具体来说,请参阅指令描述中的以下引文VPGATHERDD(第 389 页):

DISP: optional 1, 2, 4 byte displacement;
DATA_ADDR = BASE_ADDR + (SignExtend(VINDEX[i+31:i])*SCALE + DISP;

由于您可以使用 1/2/4 字节位移,我会假设整个内存地址是一个字节地址。虽然它可能不是一个常见的应用程序,但在某些情况下,您可能希望从未对齐的地址中读取 32 位或 64 位值。与 ARM 相比,这是 x86 架构更灵活的事情之一。如果需要,您可以灵活地执行未对齐的访问,而不是像其他人那样触发 CPU 异常。

于 2013-04-24T14:44:30.740 回答
1

为什么要从未对齐的地址加载(即使用比例 < 4)?

未对齐的负载不是 scale < element size 的唯一用例。您可能只有预缩放字节偏移的索引。或者考虑对指向结构的指针数组进行矢量化循环:您可以使用零的基本“地址”或结构中的小整数偏移量来收集。

支持这个用例是英特尔设计 asm 指令来支持这个用例的一个原因,因为收集应该帮助编译器自动矢量化更多代码。它也很自然地适合 VSIB 字节在机器代码编码中非常接近 SIB,但它们可以很容易地预先偏置比例因子,让您选择比例 = 4、8、16、32(或 8 ,16,32,64 用于 qword 集合)具有 2 位比例字段。

大于元素大小的比例因子在许多情况下也不是很明显有用,并且很容易在收集之前使用单个左移指令来模拟。但是要解决一个内置的比例因子是不可能的,因此允许未缩放的索引显然是更灵活的设计选择。


其他用例:收集 16 位元素。使用 32 位聚集并在聚集后屏蔽每个元素的上半部分。(或者只是让它拿着垃圾)。如果您的任何索引都是奇数(比例因子为 2),这将导致负载未对齐,因此如果它们跨越 4k 边界(与真正的 16 位收集不同),它可能会很慢。

您还可以想象使用聚集作为解压缩函数的一部分,在经过一些解码后,您有一个偏移向量到缓冲区,并且您需要任意 4 字节或 8 字节的数据窗口。

于 2017-08-26T02:33:10.313 回答