我的目标是开发代码,这些代码在可用时使用SIMD指令进行编译,而在不可用时进行编译。更具体地说,在我的C代码中,我正在进行显式SIMD调用,并根据我提取的处理器信息检查这些调用是否有效。
我有一堆问题,但经过足够的打字后SO指出: Detecting SIMD instruction sets to be used with C++ Macros in Visual Studio 2015
唯一剩下的问题是/arch
标志如何影响显式SIMD代码?即使没有设置拱门,这仍然有用吗?例如,我可以在没有/ arch:AVX2的情况下编写AVX2调用吗?
答案 0 :(得分:2)
这里有几个答案。
首先,经典的Intel 32位x86代码使用x87指令集进行浮点运算,编译器将使用x87的float
和double
类型生成代码。很长一段时间,这是构建32位时Visual C ++编译器的默认行为。您可以强制它使用带有/arch:IA32
的32位代码 - 此开关对64位无效。
对于AMD64 64位代码(英特尔也采用64位代码,一般称为x64),x87指令集与3DNow一起被弃用!在64位模式下运行时,以及Intel MMX指令。所有float
和double
类型代码都是使用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