【问题标题】:C++ convert SSE code to AVXC++ 将 SSE 代码转换为 AVX
【发布时间】:2013-09-03 08:48:33
【问题描述】:

在您的帮助下,我在我的代码(下面的示例)中使用了 SSE,显着提升了性能,我想知道是否可以通过使用 AVX 的 256 位寄存器来改进这种提升。

int result[4] __attribute__((aligned(16))) = {0};
__m128i vresult = _mm_set1_epi32(0);
__m128i v1, v2, vmax;
    for (int k = 0; k < limit; k += 4) {
        v1 = _mm_load_si128((__m128i *) & myVector[positionNodeId + k]);
        v2 = _mm_load_si128((__m128i *) & myVector2[k]);
        vmax = _mm_add_epi32(v1, v2);
        vresult = _mm_max_epi32(vresult, vmax);
    }
_mm_store_si128((__m128i *) result, vresult);
return max(max(max(result[0], result[1]), result[2]), result[3]); 

所以,我有 3 个问题:如何将上述相当简单的 SSE 代码转换为 AVX?我应该为此导入什么标题?我应该告诉我的 gcc 编译器(而不是 -sse4.1)什么标志才能使 AVX 工作?

提前致谢。为您提供帮助。

【问题讨论】:

  • 那你有试过自己解决吗? [顺便说一句,SSE中是否存在水平最大值,以保存最后一行,这在AVX中会更糟]
  • 您能否告诉(对美国感兴趣的任何人)您获得了哪些性能改进并与哪些代码进行比较?
  • @MatsPetersson,据我所知,SSE/AVX 中没有一般的水平最大值/最小值。我知道的唯一指令是_mm_minpos_epu16。否定可以用于最大值。但这仅适用于 16 位无符号字。
  • 如您所见,max 命令仅在循环外运行一次。所以,这真的没什么大不了的
  • 在这段代码中,limit = 64。此外,这段代码运行了数千次 (30,000-1,000,000),我得到了 10-20% 的可靠改进。

标签: c++ sse cpu-registers avx


【解决方案1】:
1.) This code can be easily converted to AVX2 (see below)
2.) #include <x86intrin.h>
3.) compile with -mavx2

您需要一个支持 AVX2 的 CPU。目前只有 Intel Haswell 处理器支持此功能。我还没有 Haswell 处理器,所以我无法测试代码。

    int result[8] __attribute__((aligned(32))) = {0};
    __m256i vresult = _mm256_set1_epi32(0);
    __m256i v1, v2, vmax;

    for (int k = 0; k < limit; k += 8) {
        v1 = _mm256_load_si256((__m256i *) & myVector[positionNodeId + k]);
        v2 = _mm256_load_si256((__m256i *) & myVector2[k]);
        vmax = _mm256_add_epi32(v1, v2);    
        vresult = _mm256_max_epi32(vresult, vmax);
    }
    return horizontal_max_Vec8i(vresult);
    //_mm256_store_si256((__m256i *) result, vresult);
    //int mymax = result[0];
    //for(int k=1; k<8; k++) {
    //    if(result[k]>mymax) mymax = result[k];
    //}
    //return mymax;

编辑:我怀疑由于您只运行了 64 个元素,因此水平最大值的计算时间很小但并非微不足道。我想出了一个用于 SSE 的 horizontal_max_Vec4i 函数和一个用于 AVX 的 horizontal_max_Vec8i 函数(它不需要 AVX2)。尝试将max(max(max(result[0], result[1]), result[2]), result[3]) 替换为horizontal_max_Vec4i

int horizontal_max_Vec4i(__m128i x) {
    __m128i max1 = _mm_shuffle_epi32(x, _MM_SHUFFLE(0,0,3,2));
    __m128i max2 = _mm_max_epi32(x,max1);
    __m128i max3 = _mm_shuffle_epi32(max2, _MM_SHUFFLE(0,0,0,1));
    __m128i max4 = _mm_max_epi32(max2,max3);
    return _mm_cvtsi128_si32(max4);
}

int horizontal_max_Vec8i(__m256i x) {
    __m128i low = _mm256_castsi256_si128(x);
    __m128i high = _mm256_extractf128_si256(x,1);
    return horizontal_max_Vec4i(_mm_max_epi32(low,high));
}

【讨论】:

  • 我可以使用 Ivy 桥 (i7-3770) 和 Vischera (FX-8350)。因此,此代码不会使用这些工作站支持的普通 AVX 运行,只能使用 Haswell (4770...) 运行。对吗?
  • 没错。 AVX 没有大多数 256 位整数指令。为此,您需要 AVX2。
  • 在我的 FX-8350 中无法识别 _mm256_add_epi32 和 _mm256_max_epi32。另一方面 _mm256_store_si256 和 _mm256_load_si256 似乎没问题。我可以用 2 个 _mm128_add_epi32 类型函数替换 _mm256_add_epi32 吗?是否(以及如何)可能?
  • @AlexandrosE。您必须获取 AVX 寄存器的高位和低位部分。做__m128i low = _mm256_castsi256_si128(ymm)__m128i high = _mm256_extractf128_si256(ymm,1)
  • 水平最大值在循环之外(所以不是 64 个元素)而是 4 个。因此,您的水平 SSE 最大值版本较慢。
猜你喜欢
  • 2013-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多