是否可以在SIMD指令中进行比较并在发生某些情况时交换值。换句话说,我有4个整数:
(100 5) (1 42)
我希望收到:
(5 100) (1 42)
即。我想比较成对(第一个值与第二个和第三个与第四个),如果左操作数更大 - 交换值。是否可以只使用1个SIMD?
P.S。:这是我第一次尝试使用SIMD,而且我可能使用了错误的术语 - 如果我错了,请修理我。
答案 0 :(得分:4)
对于支持AVX2的系统,有一个使用min / max并与imm
混合的解决方案(其中1个周期延迟,而变量1周期为2个周期)。
以下代码有3个周期的延迟,并且HSW +
的吞吐量应小于2个周期__m128i tmp = _mm_shuffle_epi32(in, _MM_SHUFFLE(2,3,0,1));
__m128i min = _mm_min_epi32(in, tmp);
__m128i max = _mm_max_epi32(in, tmp);
// __m128i res = _mm_blend_epi32(min, max, 0xA); // AVX2 only
__m128i res = _mm_blend_epi16(min, max, 0xCC); // SSE4.1
我已经在我的HSW系统上测试了它(处理20000对100K次),它的性能比stgatilov
CMP + VARIABLE BLEND 1.18sec
MIN/MAX + BLEND_32 0.87sec // AVX2 only code
MIN/MAX + BLEND_PS 0.86sec // SSE
MIN/MAX + PLEND_16 0.88sec // Preferred for SSE
更新:每stgatilov
'评论如下。所有MIN / MAX实现都具有几乎相同的性能(很可能只是插入内存b / w)
答案 1 :(得分:3)
您似乎希望在单个XMM寄存器中对32位整数对进行排序。当然没有现成的指令,但你可以用SSE4.1( beware:代码未经测试)的一些指令来完成:
//input = [100, 5, 1, 42]
__m128i swapped = _mm_shuffle_epi32(input, _MM_SHUFFLE(2,3,0,1)); // [5, 100, 42, 1]
__m128i comp = _mm_cmplt_epi32(input, swapped); // [0, -1, -1, 0]
comp = _mm_xor_si128(comp, _mm_set_epi32(-1, 0, -1, 0)); // [0, 0, -1, -1]
input = _mm_blendv_epi8(swapped, input, comp); // [5, 100, 1, 42]
在Ivy Bridge上似乎是7 uops并且需要2个CPU周期(吞吐量)。
如果需要,可以轻松移植到AVX2。