与SIMD内部函数进行比较和交换
Compare and swap with SIMD intrinsics
是否可以在SIMD指令中进行比较,并在某些情况下交换值。换句话说,我有4个整数:
(100 5) (1 42)
我想收到:
(5 100) (1 42)
。我想两两比较(第一个值与第二个值,第三个值与第四个值),如果左操作数更大-交换值。有可能只使用1个SIMD吗?
注::这是我第一次尝试SIMD,可能我使用了错误的术语-请修复我,如果我错了。
对于支持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
UPDATE: Per stgatilov
'注释如下。所有的MIN/MAX实现几乎都有相同的性能(很可能只是卡在内存中)
似乎您想在单个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 up,占用2个CPU周期(吞吐量)。
如果需要,它可以很容易地移植到AVX2。
相关文章:
- shell排序中的交换和比较
- 不正确的比较和交换计数器输出用于快速排序功能
- 原子值的部分比较和完全交换
- 跟踪选择排序中的交换和比较次数
- 如何在C 中实施简单的比较和交换共享计数器
- 为什么比较和交换操作同时存在免费函数和成员函数?
- 计数交换/比较合并排序算法的数字
- 通过比较数组中的相邻元素来计算交换次数
- 使用C++原子库,我应该使用什么样的内存顺序进行加载,然后进行比较交换
- 128位比较和交换固有
- std::atomic<int*>::load 应该做一个比较和交换循环吗?
- 互锁。比较交换<Int> 使用大于或小于而不是相等
- 如何将比较和交换用于任何共享数据结构的免等待互斥
- 你能用lambda比较器交换std::队列吗
- C++11比较和交换获取/释放语义
- 原子比较运算符(无交换)
- C++中比较和交换
- 比较和交换三个原子变量
- 如何在C++中获取快速排序的移动,交换和比较计数
- 比较交换原子操作vs加载链接/存储条件操作