奇怪的gcc6.1-O2编译行为

奇怪的gcc6.1-O2编译行为,gcc,optimization,x86,x86-64,compiler-optimization,Gcc,Optimization,X86,X86 64,Compiler Optimization,我使用gcc-O2-march=native标志编译相同的基准测试。然而,有趣的是,当我看到objdump时,它实际上产生了一些指令,比如vxorpd,等等,我认为只有在启用-ftree vectorize时才会出现这些指令(默认情况下,-O2不应该启用它),这些包装好的说明书不见了。任何遇到类似情况的人都可以给出一些解释吗?谢谢。是对两个压缩双精度浮点值执行位逻辑异或的经典SSE2指令 VXORPD是同一指令的矢量版本。本质上,它是经典的SSE2XORPD指令,具有。这就是“V”前缀在操作码中

我使用gcc
-O2-march=native
标志编译相同的基准测试。然而,有趣的是,当我看到
objdump
时,它实际上产生了一些指令,比如
vxorpd
,等等,我认为只有在启用
-ftree vectorize
时才会出现这些指令(默认情况下,
-O2
不应该启用它),这些包装好的说明书不见了。任何遇到类似情况的人都可以给出一些解释吗?谢谢。

是对两个压缩双精度浮点值执行位逻辑异或的经典SSE2指令

VXORPD
是同一指令的矢量版本。本质上,它是经典的SSE2
XORPD
指令,具有。这就是“V”前缀在操作码中的含义。它是随AVX(Advanced Vector Extensions)引入的,并且在支持AVX的任何体系结构上都受支持。(实际上有两种版本,一种是在128位AVX寄存器上工作的VEX.128编码版本,另一种是在256位AVX2寄存器上工作的VEX.256编码版本。)

所有传统SSE和SSE2指令都可以添加VEX前缀,使其具有三个操作数的形式,并允许它们与其他新AVX指令进行更有效的交互和调度。它还避免了。否则,这些新编码将保留相同的行为。因此,只要目标体系结构支持,编译器通常会生成这些指令的VEX前缀版本。显然,在您的例子中,
march=native
指定的架构至少支持AVX

在GCC和Clang上,即使关闭了优化(
-O0
),也会发出这些指令,因此在启用优化时肯定会得到它们。
-ftree vectorize
开关和任何其他特定于矢量化的优化开关都不需要打开,因为这实际上与代码矢量化无关。更准确地说,代码流没有改变,只是指令的编码没有改变

您可以通过最简单的代码看到这一点:

double Foo()
{
   return 0.0;
}
这就解释了为什么在使用
-march=native
开关编译64位版本时,会看到
VXORPD
及其朋友

这就留下了一个问题,为什么在抛出
-m32
开关(这意味着为32位平台生成代码)时看不到它。针对这些平台时,SSE和AVX指令仍然可用,我相信它们在某些情况下会被使用,但由于32位ABI的显著差异,它们不能如此频繁地使用。具体而言,32位ABI要求在x87浮点堆栈上返回浮点值。因为这需要使用x87浮点指令,所以优化器倾向于使用这些指令,除非它对代码部分进行了大量矢量化。这是唯一一次真正有意义的将值从x87堆栈洗牌到SIMD寄存器再洗牌回来。否则,这将导致性能损失,几乎没有实际好处

你也可以在行动中看到这一点。通过抛出
-m32
开关,查看输出中的变化:

Foo():
        fldz
        ret
是用于在浮点堆栈顶部加载常量零的x87 FPU指令,可以在该堆栈中返回给调用方

显然,随着代码变得更加复杂,您更有可能更改优化器的启发式,并说服它发出SIMD指令。如果启用基于矢量化的优化,则更有可能执行此操作。

是对两个压缩双精度浮点值执行位逻辑异或的经典SSE2指令

VXORPD
是同一指令的矢量版本。本质上,它是经典的SSE2
XORPD
指令,具有。这就是“V”前缀在操作码中的含义。它是随AVX(Advanced Vector Extensions)引入的,并且在支持AVX的任何体系结构上都受支持。(实际上有两种版本,一种是在128位AVX寄存器上工作的VEX.128编码版本,另一种是在256位AVX2寄存器上工作的VEX.256编码版本。)

所有传统SSE和SSE2指令都可以添加VEX前缀,使其具有三个操作数的形式,并允许它们与其他新AVX指令进行更有效的交互和调度。它还避免了。否则,这些新编码将保留相同的行为。因此,只要目标体系结构支持,编译器通常会生成这些指令的VEX前缀版本。显然,在您的例子中,
march=native
指定的架构至少支持AVX

在GCC和Clang上,即使关闭了优化(
-O0
),也会发出这些指令,因此在启用优化时肯定会得到它们。
-ftree vectorize
开关和任何其他特定于矢量化的优化开关都不需要打开,因为这实际上与代码矢量化无关。更准确地说,代码流没有改变,只是指令的编码没有改变

您可以通过最简单的代码看到这一点:

double Foo()
{
   return 0.0;
}
这就解释了为什么在使用
-march=native
开关编译64位版本时,会看到
VXORPD
及其朋友

这就留下了一个问题,为什么在抛出
-m32
开关(这意味着为32位平台生成代码)时看不到它。针对这些平台时,SSE和AVX指令仍然可用,我相信它们在某些情况下会被使用,但它们不能被如此频繁地使用,因为它们与我的指令存在显著差异
gcc -O2 -fverbose-asm -S -o test.S test.c