如何使用vindex和_mm_i32gather_epi32缩放来收集元素?

时间:2018-06-15 23:29:25

标签: c++ sse simd intrinsics avx2

英特尔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

如果我正确解析内容,那么vindexscale)是用于创建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,4vindex选择数组索引scale

1 个答案:

答案 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<<242<<24等。打印为一个大的64位整数更难发现。

这个来源的比例变化= 1 - &gt; 4,您的聚集是一个身份映射:

(gdb) p  $xmm7.v4_int32
$2 = {13, 9, 5, 1}

我不确定GDB是否有一种方便的方法来打印__m128i变量的元素而不知道它在哪个寄存器中。