使用`__m256i`中的值有效地访问数组 - SIMD

时间:2017-08-07 20:04:54

标签: c++ arrays simd avx2

我们举例来说,我有2个变量__m256i,名为rowscols,其中的值为:

rows: 0, 2, 7, 5, 7, 2, 3, 0
cols: 1, 2, 7, 5, 7, 2, 2, 6

现在,这些值代表8个点的xy位置,因此,在这种情况下,我会得到以下几点:

p0: [0, 1], p1: [2, 2], p2: [7, 7], p3: [5, 5]
p4: [7, 7], p5: [2, 2], p6: [3, 2], p7: [0, 6]

我还有一个名为lut的数组,其值为int类型:

lut: [0, 1, 2, 3, ..., 60, 61, 62, 63]

我想要做的是使用rowscols变量中的这些位置值,使用它访问lut数组并创建一个新的__m256ilut访问过的值。

我知道如何执行此操作的方法是将rowscols值存储在两个大小为8的int数组中,然后从lut中读取值一次一个数组,然后使用_mm256_set_epi32()创建新的_m256i值。

这有效,但在我看来效率非常低。所以我的问题是如果有更快的方法可以做到这一点。

请注意,这些值仅用于更具体的示例,而lut不需要具有有序值或大小为64.

谢谢!

1 个答案:

答案 0 :(得分:6)

您可以使用avx2 gather instruction构建解决方案,如此

// index = (rows << 3) + cols;
const __m256i index = _mm256_add_epi32( _mm256_slli_epi32(rows, 3), cols);
// result = lut[index];
const __m256i result = _mm256_i32gather_epi32(lut, index, 4);

请注意,在当前的CPU上,收集指令具有相当大的延迟,因此除非您在实际使用result之前可以交错某些指令,否则这可能不值得使用。

解释因子4:<{p>中的scale因子

__m256i _mm256_i32gather_epi32 (int const* base_addr, __m256i vindex, const int scale)

被视为实际的字节偏移量,即每个索引的返回值为:

*(const int*)((const char*) base_addr + scale*index)

我不知道该行为是否有很多用例(也许这是为了能够访问具有1byte或2byte条目的LUT(之后需要一些屏蔽))。也许这只是允许的,因为缩放4是可能的,而缩放1/4或1/2则不会(如果有人真的需要缩放)。