使用AVX2收集指令时加载地址计算

Pau*_*l R 13 x86 sse simd avx2

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

__m128i _mm_i32gather_epi32 (int const * base, __m128i index, const int scale);
Run Code Online (Sandbox Code Playgroud)

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

load_addr = base + index[i] * scale;               // (1) element addressing ?
Run Code Online (Sandbox Code Playgroud)

要么:

load_addr = (char *)base + index[i] * scale;       // (2) byte addressing ?
Run Code Online (Sandbox Code Playgroud)

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

Evg*_*uev 10

收集指令没有任何对齐要求.因此,不允许字节寻址会限制太多.

其他原因是一致性.使用SIB寻址,我们显然有字节地址:

MOV eax, [rcx + rdx * 2]
Run Code Online (Sandbox Code Playgroud)

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

VPGATHERDD ymm0, [rcx + ymm2 * 2], ymm3
Run Code Online (Sandbox Code Playgroud)

至于字节寻址的实际使用,我们可以有一个24位彩色图像,其中每个像素是3字节对齐的.我们可以使用单个VPGATHERDD指令加载8个像素,但仅当VSIB中的"scale"字段为"1"并VPGATHERDD使用字节寻址时.


Jas*_*n R 5

根据此处提供的英特尔AVX编程参考文档中的描述,看起来聚集指令使用字节寻址.具体而言,请参阅说明说明中的以下引用VPGATHERDD(第389页):

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

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