使用 SSE 进行比较和提取

Posted

技术标签:

【中文标题】使用 SSE 进行比较和提取【英文标题】:Comparison and Extraction using SSE 【发布时间】:2012-05-12 13:48:29 【问题描述】:

使用 SSE 指令对两个整数寄存器进行成对比较和提取相等元素的最佳方法是什么?例如,如果a = [6 4 7 2]b = [2 4 9 2](每个寄存器包含四个32 位整数),则结果应为[4 2 x x]。此问题的另一种形式是如何获得相等元素的二进制掩码 (..0101b),该掩码可用于改组或作为索引以在预计算表中查找改组指令的参数。

【问题讨论】:

减法会将相等的数对变成0。 【参考方案1】:

不可能用一条指令提取和移动相等的元素。但是使用pcmpeqd 可以轻松实现相等元素的掩码:

__m128i zero = _mm_set1_epi32(0);
__m128i a = _mm_set_epi32(6, 4, 7, 2);
__m128i b = _mm_set_epi32(2, 4, 9, 2);

__m128i mask = _mm_cmp_epi32(a, b);     // mask is now 0, -1, 0, -1
mask = _mm_sub_epi32(zero, mask);       // mask is now 0,  1, 0,  1

编辑: 如果你想要一个带有 shuffle 常量的查找表的索引,你需要额外的操作。喜欢

static const __m128i zero = _mm_set1_epi32(0);
static const __m128i bits = _mm_set_epi32(1,2,4,8);

__m128i a = _mm_set_epi32(6, 4, 7, 2);
__m128i b = _mm_set_epi32(2, 4, 9, 2);

__m128i bitvector = _mm_and_si128(bits, _mm_cmp_epi32(a, b));
bitvector = _mm_hadd_epi32(bitvector, bitvector);
bitvector = _mm_hadd_epi32(bitvector, bitvector);
// now a index from 0...15 is the the low 32 bit of bitvector

可能有比使用查找表计算 shuffle 更好的算法,可能直接使用 De Bruijn 乘法计算 shuffle。 OTOH,如果您有超过 4 个整数要比较,那么额外的 4 个整数只会以 一个 额外 phaddd 为代价。

【讨论】:

我实际上的意思是一个位掩码,它可以直接用于改组指令或作为一个小索引在预计算表中查找掩码,即在本例中为mask = ..0101b = 5d【参考方案2】:

我可能会使用drhirsch 建议的变体:

int index = _mm_movemask_ps((__m128)_mm_cmp_epi32(a, b));

这为您提供了相同的索引,可用于仅使用两个操作查找 shuffle 掩码。

【讨论】:

以上是关于使用 SSE 进行比较和提取的主要内容,如果未能解决你的问题,请参考以下文章

SSE 比较内在 - 如何从比较中获得 1 或 0?

在 C++ 中对整数数组进行线性搜索时,SSE 比较无法按预期工作

将 16 字节字符串与 SSE 进行比较

在 SSE 中进行比较时的奇怪行为

SSE 从 __m128 中提取整数用于索引数组

MMX 与 SSE2 性能比较