用visual studio编译代码时arch参数怎么用?
How is the arch parameter used when compiling code with visual studio?
我的目标是开发在 SIMD 指令可用时使用 SIMD 指令编译的代码,在它们不可用时不使用。更具体地说,在我的 C 代码中,我进行了明确的 SIMD 调用,并根据我正在提取的处理器信息检查这些调用是否有效。
我有很多问题,但在输入足够多之后,SO 指出了我:
Detecting SIMD instruction sets to be used with C++ Macros in Visual Studio 2015
唯一剩下的问题是 /arch
标志如何影响显式 SIMD 代码?即使您的拱门未设置,这仍然有效吗?例如,我可以在没有 /arch:AVX2 的情况下编写 AVX2 调用吗?
这里有一些答案。
首先,经典的 Intel 32 位 x86 代码使用 x87 指令集进行浮点运算,编译器会使用 x87 的 float
和 double
类型生成代码。长期以来,这是 Visual C++ 编译器在构建 32 位时的默认行为。您可以通过 /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 编组规则仅处理 XMML
结果。这是为 64 位构建时 Visual C++ 编译器的默认行为。您还可以通过 /arch:SSE
或 /arch:SSE2
开关对 32 位使用相同的代码生成器——这些开关对 x64 无效,因为它们必须已经存在。
Starting with Visual C++ 2015, /arch:SSE2
is the default for 32-bit code gen and is implicitly required for all 64-bit code gen.
这将我们带到 /arch::AVX
。对于 32 位和 64 位代码生成器,这让编译器使用 VEX 前缀来编码 SSE/SSE2 指令(由我上面提到的数学编译器生成或通过显式使用编译器内部函数生成)。此编码使用 3 操作数 (dest, src1, src2)
而不是 Intel 代码的传统 2 操作数 (dest/src1, src2)
。这样做的最终结果是所有 SSE/SSE2 code-gen 都更有效地使用了可用的寄存器。这确实是使用 /arch:AVX
的大部分内容。
编译器的其他方面也使用了 /arch
开关设置,例如优化的 memcpy
和可供 [= 中的自动向量化器使用的指令集28=] 和 /Ox
构建等。编译器还假设如果您使用 /arch:AVX
它可以自由使用 SSE3、SSSE3、SSE4.1、SSE4.2 或 AVX 指令以及 SSE/SSE2.
使用 /arch:AVX2
时,您会得到与 VEX 前缀和指令集相同的行为,而且编译器可能会选择优化代码以使用 AVX2 所需的融合乘加 (FMA3) 指令。自动矢量化器也可以在激活此开关的情况下使用 AVX2 指令。
TL;DR: 如果您使用编译器内部函数,您将承担确保它们不会在运行时因无效指令异常而崩溃的责任。 /arch
开关只是让你告诉编译器在任何地方都使用高级指令集和编码。
有关详细信息,请参阅此博客系列:DirectXMath: SSE, SSE2, and ARM-NEON; SSE3 and SSSE3; SSE4.1 and SSE 4.2; AVX; F16C and FMA; AVX2; and ARM64.
我的目标是开发在 SIMD 指令可用时使用 SIMD 指令编译的代码,在它们不可用时不使用。更具体地说,在我的 C 代码中,我进行了明确的 SIMD 调用,并根据我正在提取的处理器信息检查这些调用是否有效。
我有很多问题,但在输入足够多之后,SO 指出了我: Detecting SIMD instruction sets to be used with C++ Macros in Visual Studio 2015
唯一剩下的问题是 /arch
标志如何影响显式 SIMD 代码?即使您的拱门未设置,这仍然有效吗?例如,我可以在没有 /arch:AVX2 的情况下编写 AVX2 调用吗?
这里有一些答案。
首先,经典的 Intel 32 位 x86 代码使用 x87 指令集进行浮点运算,编译器会使用 x87 的 float
和 double
类型生成代码。长期以来,这是 Visual C++ 编译器在构建 32 位时的默认行为。您可以通过 /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 编组规则仅处理 XMML
结果。这是为 64 位构建时 Visual C++ 编译器的默认行为。您还可以通过 /arch:SSE
或 /arch:SSE2
开关对 32 位使用相同的代码生成器——这些开关对 x64 无效,因为它们必须已经存在。
Starting with Visual C++ 2015,
/arch:SSE2
is the default for 32-bit code gen and is implicitly required for all 64-bit code gen.
这将我们带到 /arch::AVX
。对于 32 位和 64 位代码生成器,这让编译器使用 VEX 前缀来编码 SSE/SSE2 指令(由我上面提到的数学编译器生成或通过显式使用编译器内部函数生成)。此编码使用 3 操作数 (dest, src1, src2)
而不是 Intel 代码的传统 2 操作数 (dest/src1, src2)
。这样做的最终结果是所有 SSE/SSE2 code-gen 都更有效地使用了可用的寄存器。这确实是使用 /arch:AVX
的大部分内容。
编译器的其他方面也使用了 /arch
开关设置,例如优化的 memcpy
和可供 [= 中的自动向量化器使用的指令集28=] 和 /Ox
构建等。编译器还假设如果您使用 /arch:AVX
它可以自由使用 SSE3、SSSE3、SSE4.1、SSE4.2 或 AVX 指令以及 SSE/SSE2.
使用 /arch:AVX2
时,您会得到与 VEX 前缀和指令集相同的行为,而且编译器可能会选择优化代码以使用 AVX2 所需的融合乘加 (FMA3) 指令。自动矢量化器也可以在激活此开关的情况下使用 AVX2 指令。
TL;DR: 如果您使用编译器内部函数,您将承担确保它们不会在运行时因无效指令异常而崩溃的责任。 /arch
开关只是让你告诉编译器在任何地方都使用高级指令集和编码。
有关详细信息,请参阅此博客系列:DirectXMath: SSE, SSE2, and ARM-NEON; SSE3 and SSSE3; SSE4.1 and SSE 4.2; AVX; F16C and FMA; AVX2; and ARM64.