与 SIMD 内部函数进行比较和交换

Compare and swap with SIMD intrinsics

是否可以在 SIMD 指令中进行比较并在某些情况发生时交换值。换句话说,我有 4 个整数:

(100 5) (1 42)

我想收到:

(5 100) (1 42)

即我想成对比较(第一个值与第二个值和第三个值与第四个值),如果左操作数更大 - 交换值。是否可以仅使用 1 个 SIMD?

P.S.: 这是我第一次尝试 SIMD,可能我使用了错误的术语 - 如果我错了请修复我。

您似乎想要对单个 XMM 寄存器中的 32 位整数对进行排序。当然没有现成的说明,但是你可以用 SSE4.1 的一些指令来完成(注意: 代码未测试):

//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 微码,需要 2 CPU 个周期(吞吐量)。

如果需要,它可以很容易地移植到 AVX2。

对于支持 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

的代码高约 26%
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)