为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?

Posted

技术标签:

【中文标题】为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?【英文标题】:Why AVX2 and SSE2 bitwise OR operators are not faster than a simple | operator?为什么 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员? 【发布时间】:2019-11-13 15:31:09 【问题描述】:

我正在尝试使用 32 位整数来加速非常长的二进制向量的按位或运算。

在这个例子中,我们可以假设 nwords 是单词的数量,它是 4 和 8 的倍数。因此,没有循环提醒。这个二进制向量可以包含数千位。

此外,所有三个位向量都是使用 _align_malloc() 分配的,分别用于 SSE2 和 AVX2 的 16 位和 18 位对齐。

令我惊讶的是,以下三个标量、SSE2 和 AVX2 代码在我的 i7 CPU 上执行的时间完全相同。我没有体验到 SSE2 和 AVX2 寄存器的预期 x4 和 x8 加速。

我的 MVisual Studio 版本是 15.1。

标量代码:

void vectorOr_Scalar(unsigned int *ptr1, unsigned int *ptr2, unsigned int *out, int nwords)

    for (end = ptr1 + nwords; ptr1 < end; ptr1++, ptr2++, out++) *out = *ptr1 | *ptr2;

SSE2 代码:

void vectorOr_SSE2(unsigned int *ptr1, unsigned int *ptr2, unsigned int *out, int nwords)

    for (i = 0; i < nwords; i += 4, ptr1 += 4, ptr2 += 4, out += 4)
    
        __m128i v1 = _mm_load_si128((__m128i *)ptr1);
        __m128i v2 = _mm_load_si128((__m128i *)ptr2);
        _mm_store_si128((__m128i *)out, _mm_or_si128(v1, v2));
    

AVX2 代码:

void vectorOr_AVX2(unsigned int *ptr1, unsigned int *ptr2, unsigned int *out, int nwords)

    for (i = 0; i < nwords; i += 8, ptr1 += 8, ptr2 += 8, out += 8)
    
        __m256i v1 = _mm256_load_si256((__m256i *)ptr1);
        __m256i v2 = _mm256_load_si256((__m256i *)ptr2);
        _mm256_store_si256((__m256i *)out, _mm256_or_si256(v1, v2));
    

也许由于加载和存储之间的寄存器操作数量有限,此应用程序不适合矢量化?

【问题讨论】:

编译器现在非常聪明,你确定他们不会为你的标量情况生成类似的代码吗? 0。检查您是否启用了优化的 AVX2(否则编译器将调用向量替换函数,而无需硬件提升)。 1. 可以试试用OpenMP 加#pragma omp parallel for simd 正如@MarkRansom 所说,您的编译器可能自己想出了如何对您的函数进行矢量化。在热循环中查找vorpsvpor 指令:godbolt.org/z/MR2x8V 大家好,是的,好像马克说的。非常感谢! 我找了一个副本;我确定我已经看过问答,答案是标量版本很简单,可以自动矢量化,但没有找到任何答案。 【参考方案1】:

您没有观察到一次处理一个 unsigned 的循环和一次处理 8 个 unsigned 的 SIMD 循环之间的性能差异的原因是编译器会为您生成 SIMD 代码,以及展开循环,请参阅the generated assembly。

【讨论】:

以上是关于为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?的主要内容,如果未能解决你的问题,请参考以下文章

用于灰度到 ARGB 转换的 C++ SSE2 或 AVX2 内在函数

使用 AVX2 和范围保留的按位类型转换

AVX2中的按位非/补码[重复]

为啥按位运算符不如逻辑“和\或”运算符聪明

为啥 tslint 中不允许按位运算符?

为啥这个逻辑/按位运算返回 1?