AVX(2) 收集指令如何实际计算获取地址?

How do the AVX(2) gather instructions actually compute the fetch address?

_mm_i32gather_epi32() 的当前英特尔内在函数指南将每个子字的计算地址描述为:

addr := base_addr + SignExtend64(vindex[m+31:m]) * ZeroExtend64(scale) * 8

最后 8 个让我很困惑。假设 addrbase_addr 以字节为单位,并且 scale 取值 1、2、4 或 8,那么您只能从基地址索引 8 个字节的步幅。这是文档中的错误,还是我遗漏了什么?对于我检查过的所有收集指令,它的描述方式相同。

A previous question 引用了没有 8 的文档,这表明发生了一些变化。

注意伪代码中的下一行:

dst[i+31:i] := MEM[addr+31:addr]

显然有人认为将内存地址描述为位地址而不是字节地址是个好主意。 /捂脸。这实际上没有意义,不是任何人所期望的,甚至没有正确完成,因为他们未能将 base_addr 缩放 8。所以他们在字节地址中添加了一个位偏移量。

这只是糟糕的文档,并且是一种比链接问题中引用的先前版本更糟糕的描述方式。这只是文档更改,而不是代码含义的更改,您可以尝试编译它并查看 asm 以查看生成的实际指令。 (我对您链接的问题的回答仍然是正确的:asm 指令允许比例因子为 1、2、4 或 8,因为 2 位移位计数的编码方式与标量指令对缩放索引寻址模式的编码方式相同。所以你可以使用字节偏移向量。)

之前更好的伪代码是:

dst[i+31:i] := MEM[base_addr + SignExtend(vindex[i+31:i])*scale]

因此MEM[](虚拟地址space)正在使用计算出的字节偏移量进行索引,并且访问宽度为dst[31:0]位宽度所暗示的32位。


根据经验,内部函数通常尽可能直接映射到 asm 指令。他们不会选择以需要编译器发出的方式来定义它a vpslld ymm0, ymm1, 3 在 运行 vpgatherdd.

之前缩放变址寄存器

因此您可以查阅 asm 指令的文档(有时会有不同的伪代码,例如本例):https://www.felixcloutier.com/x86/vpgatherdd:vpgatherqd

...
    DATA_ADDR←BASE_ADDR + (SignExtend(VINDEX1[i+31:i])*SCALE + DISP;
    IF MASK[31+i] THEN
        DEST[i +31:i]←FETCH_32BITS(DATA_ADDR); // a fault exits the instruction
    FI;