VC++ 编译器没有你想象的那么聪明。以下是这些设置的工作原理。
当您构建 32 位代码并启用 SSE1 或 SSE2 时,它会启用自动矢量化到相应的指令集。
当您构建 64 位代码时,SSE1 和 SSE2 都是指令集的一部分,世界上所有 AMD64 处理器都需要同时支持这两者。这就是您收到 /arch:SSE2 警告的原因。
当您设置 AVX 时,编译器会做 2 件事,启用自动矢量化到 AVX1,还将指令编码(对于所有这些,包括 SSE、AVX、手动矢量化和自动矢量化)从 legacy 切换到VEX。VEX 是个好东西,可以将未对齐的 RAM 读取融合到其他指令中。它还解决了可能影响性能的依赖性问题,VEX 编码vaddps xmm0, xmm0, xmm1
将更高的 16 字节归零ymm0
,而传统编码addps xmm0, xmm0, xmm1
将数据保留在那里。
当您设置 AVX2 时,它会进行一些小的优化,最值得注意的是_mm_set1_epi32
可能会编译成vpbroadcastd
. 也像 AVX1 一样将编码切换到 VEX。
注意我用粗体标记了自动。Microsoft 编译器不执行运行时调度或 cpuid 检查,并且自动矢量化器不使用 SSE3 或 4.1。如果您正在编写手动矢量化代码,编译器将不会执行回退,而是会发出您要求的任何指令。存在时,AVX/AVX2 设置仅影响其编码。
如果您想编写使用 SSE3、SSSE3、SSE 4.1、FMA3、AES、SHA 等的手动矢量化代码,则无需启用任何东西。您只需要包含相关的头文件,并理想地确保在运行时 CPU 拥有它们。对于最后一部分,我通常__cpuid
在启动时尽早调用并检查这些位,这是为了显示有关不受支持的 CPU 的可理解的错误消息,而不是稍后的硬崩溃。