如何在新CPU上利用AVX2的同时还支持旧CPU?

时间:2019-04-08 10:09:59

标签: c++ visual-studio optimization simd

我有一些图像处理算法,该算法在三个版本中实现:

  1. 使用x64指令集(rax,rbx,...寄存器)
  2. 使用SSE指令集(xmm寄存器)
  3. 使用AVX2指令集(ymm寄存器)

每个优化步骤都会提高性能。但是,我需要在仅支持SSE的旧CPU上运行它(我在Visual Studio上使用x64平台,因此我所有的CPU都支持SSE)。

在Visual Studio中,有一个名为“启用增强指令集”的设置,必须将其设置为/arch:AVX2,才能在较新的CPU上获得最佳性能。但是,使用此设置,可执行文件在我的旧CPU上崩溃。如果我将“启用增强指令集”设置为/arch:SSE2,则我的可执行文件可以在较旧的CPU上运行,但是在较新的CPU上无法获得最佳性能。

我使用较新的CPU测量了编译器标志和指令集所有组合的执行速度。总结在下表中。

Instruction set ||        Compilation flags
which I use     ||     /arch:SSE     /arch:AVX2
----------------++------------------------------------
x64             ||     bad (4.6)      bad (4.5)
SSE             ||     OK  (1.9)      bad (5.3)
AVX2            ||     bad (3.2)     good (1.4)

我的矢量化代码使用内在函数,就像这样:

// AVX2 - conversion from 32-bit to 16-bit
temp = _mm256_packus_epi32(input[0], input[1]);
output = _mm256_permute4x64_epi64(temp, 0xd8);
// SSE - choosing one of two results using a mask
result = _mm_blendv_epi8(result0, result1, mask);

我猜想,如果Visual Studio获得/arch:AVX2编译标志,它将执行所有必需的特定于AVX2的优化,例如emitting vzeroupper。因此,我看不到如何使用相同的已编译可执行文件在两种类型的CPU上获得最佳性能。

这可能吗?如果是,我需要给Visual Studio编译器哪些编译标志?

1 个答案:

答案 0 :(得分:2)

英特尔这样做的方法是CPU调度(请检查英特尔编译器文档中的ax标志)。 ax标志特定于Intel编译器,并进行隐式CPU调度。它在VS上不可用,因此您必须手动进行。

在代码的开头,检查CPU功能并在某个位置设置一些全局标志。

然后,当您调用其中一个函数时,首先要检查标志状态以查看实际要调用的函数。

因此,您最终得到了不同的功能风格。为了解决这个问题,您可以将它们放在其他特定的命名空间中(例如libsimdpp进行命名),或者手动修改函数名(例如Intel编译器进行修改)。

此外,任何64位CPU都通过构造支持SSE2,因此情况1不存在。