英特尔Intrinsic Guide说:
__m128i _mm_i32gather_epi32 (int const* base_addr, __m128i vindex, const int scale)
和
描述
使用32位索引从内存中收集32位整数。 32位 元素从base_addr开始的地址加载并偏移 vindex中的每个32位元素(每个索引按因子缩放) 规模)。收集的元素合并到dst。比例应为1,2,4 或者8。
操作
FOR j := 0 to 3 i := j*32 dst[i+31:i] := MEM[base_addr + SignExtend(vindex[i+31:i])*scale] ENDFOR dst[MAX:128] := 0
如果我正确解析内容,那么vindex
(scale
)是用于创建base_addr
的{{1}}的索引。
下面我正在尝试创建__m128i result
。也就是说,从1开始每4个元素。
val = arr[1] << 96 | arr[5] << 64 | arr[9] << 32 | arr[13] << 0
但是当我检查$ cat -n gather.cxx
1 #include <immintrin.h>
2 typedef unsigned int u32;
3 int main(int argc, char* argv[])
4 {
5 u32 arr[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
6 __m128i idx = _mm_set_epi32(1,5,9,13);
7 __m128i val = _mm_i32gather_epi32(arr, idx, 1);
8 return 0;
9 }
时:
val
我似乎错误地使用了(gdb) n
6 __m128i idx = _mm_set_epi32(1,5,9,13);
(gdb) n
7 __m128i val = _mm_i32gather_epi32(arr, idx, 1);
(gdb) n
8 return 0;
(gdb) p val
$1 = {0x300000004000000, 0x100000002000000}
。看来我正在选择索引vindex
。
如何使用1,2,3,4
和vindex
选择数组索引scale
?
答案 0 :(得分:2)
您的数组元素宽度为4个字节。因此,当使用元素索引而不是字节偏移时,在VSIB寻址模式下使用比例因子4 。
int const* base_addr
参数的类型为int
,但在任何时候都不是用它做的任何C指针数学。它直接馈送到asm指令,因此您需要处理字节偏移。 (并且希望如果你想从uint64_t[]
或char[]
中获取dwords,也要注意严格的别名。)它也可以是const void*
。
如果内在函数将您的比例因子乘以4,则您无法将其与字节偏移一起使用,仅与int
索引一起使用。 asm指令可以使用通常的x86寻址模式编码来缩放1,2,4或8:2位移位计数。
步幅为4的步幅索引从1开始,除了每个元素的高字节外,到处都是零。即,它从数组的开始偏移1个字节,x86是小端。
请注意,您没有获取1,2,3,4
,您获得了1<<24
,2<<24
等。打印为一个大的64位整数更难发现。
这个来源的比例变化= 1
- &gt; 4
,您的聚集是一个身份映射:
(gdb) p $xmm7.v4_int32
$2 = {13, 9, 5, 1}
我不确定GDB是否有一种方便的方法来打印__m128i
变量的元素而不知道它在哪个寄存器中。