使用visual studio编译代码时如何使用arch参数?

时间:2018-06-13 00:59:46

标签: visual-c++ compiler-optimization simd intrinsics avx

我的目标是开发代码,这些代码在可用时使用SIMD指令进行编译,而在不可用时进行编译。更具体地说,在我的C代码中,我正在进行显式SIMD调用,并根据我提取的处理器信息检查这些调用是否有效。

我有一堆问题,但经过足够的打字后SO指出: Detecting SIMD instruction sets to be used with C++ Macros in Visual Studio 2015

唯一剩下的问题是/arch标志如何影响显式SIMD代码?即使没有设置拱门,这仍然有用吗?例如,我可以在没有/ arch:AVX2的情况下编写AVX2调用吗?

1 个答案:

答案 0 :(得分:2)

这里有几个答案。

首先,经典的Intel 32位x86代码使用x87指令集进行浮点运算,编译器将使用x87的floatdouble类型生成代码。很长一段时间,这是构建32位时Visual C ++编译器的默认行为。您可以强制它使用带有/arch:IA32的32位代码 - 此开关对64位无效。

对于AMD64 64位代码(英特尔也采用64位代码,一般称为x64),x87指令集与3DNow一起被弃用!在64位模式下运行时,以及Intel MMX指令。所有floatdouble类型代码都是使用SSE / SSE2生成的,但不一定使用XMM寄存器的完整4个浮点数或2个双元素宽度。相反,编译器通常会生成仅使用XMML的SSE / SSE2指令的标量版本 - 事实上,__fastcall调用约定和64位的.NET编组规则仅处理{{1 }} 结果是。这是构建64位时Visual C ++编译器的默认行为。您也可以通过XMML/arch:SSE开关对32位使用相同的codegen - 这些开关对x64无效,因为它们必须已存在。

  

从Visual C ++ 2015开始,/arch:SSE2是32位代码的默认值,并且对于所有64位代码都是隐式要求的。

这将我们带到/arch:SSE2。对于32位和64位codegen,这让编译器使用VEX前缀来编码SSE / SSE2指令(由我上面讨论的数学编译器生成或通过显式使用编译器内在函数)。对于英特尔代码,此编码使用3个操作数/arch::AVX而不是传统的2操作数(dest, src1, src2)。最终结果是所有SSE / SSE2代码生成器都可以更有效地使用可用的寄存器。这实际上是使用(dest/src1, src2)获取的大部分内容。

编译器的其他方面也使用/arch:AVX开关设置,例如优化的/arch和可用于{{1}中的自动矢量化器的指令集编译器还假设如果你使用memcpy,它可以自由使用SSE3,SSSE3,SSE4.1,SSE4.2或AVX指令以及SSE / SSE2}和/O2构建等。

使用/Ox,您可以获得与VEX前缀和指令集相同的行为,此外编译器可以选择优化代码以使用AVX2所需的融合乘法加法(FMA3)指令。自动矢量化器也可以在此开关激活时使用AVX2指令。

TL; DR:如果使用编译器内在函数,则由于指令异常无效,您需要确保它们在运行时不会崩溃。 /arch:AVX开关只是告诉编译器在任何地方使用高级指令集和编码。

有关详细信息,请参阅此博客系列: DirectXMath: SSE, SSE2, and ARM-NEON; SSE3 and SSSE3; SSE4.1 and SSE 4.2; AVX; F16C and FMA;和AVX2