我正在编译使用gcc -O2 -march = native标志的相同基准。然而,有趣的是,当我看着objdump时,它实际上产生了一些指令,如vxorpd等,我认为这应该只在启用了ftree-vectorize时出现(并且O2不应该默认启用此功能)?如果我添加了-m32标志在32位指令中编译时,这些打包的指令消失了。任何遇到类似情况的人都可以提供一些解释?谢谢。奇怪的gcc6.1 -O2编译行为
回答
XORPD
是传统的SSE2指令,它在两个压缩的双精度浮点值上执行按位逻辑异或。
VXORPD
是该指令的矢量版本。实质上,它是带有VEX prefix的经典SSE2 XORPD
指令。这就是操作码中“V”前缀的意思。它与AVX(高级矢量扩展)一起引入,并且在任何支持AVX的架构上都受支持。 (实际上有两个版本,适用于128位AVX寄存器的VEX.128编码版本和适用于256位AVX2寄存器的VEX.256编码版本。)
所有传统SSE SSE2指令可以添加一个VEX前缀,给它们一个三操作数的形式,并允许它们与其他新的AVX指令进行更有效的交互和调度。它也避免了the high cost of transitions between VEX and non-VEX modes。否则,这些新的编码保持相同的行为。因此,编译器通常会在目标体系结构支持它们时生成这些指令的VEX前缀版本。显然,在你的情况下,march=native
指定了一个至少支持AVX的体系结构。
在GCC和Clang上,即使优化关闭(-O0
),实际上也会发出这些指令,所以启用优化时您肯定会获得这些指令。 -ftree-vectorize
开关以及任何其他矢量化特定的优化开关都不需要开启,因为这实际上与矢量化代码无关。更确切地说,代码流没有改变,只是指令的编码。
你可以想到的最简单的代码,看到这一点:
double Foo()
{
return 0.0;
}
Foo():
vxorpd xmm0, xmm0, xmm0
ret
所以这解释了为什么你看到VXORPD
和它的朋友,当你编译一个64位的建设与-march=native
开关。
这留下了为什么你不要看到它时,你扔-m32
开关(这意味着为32位平台生成代码)。针对这些平台时,SSE和AVX指令仍然可用,并且我相信它们将在某些情况下使用,但由于32位ABI的显着差异,它们不能经常使用。具体而言,32位ABI要求在x87浮点堆栈上返回浮点值。由于这需要使用x87浮点指令,因此优化程序倾向于坚持使用这些指令,除非它严格地向量化一段代码。这是将x87堆栈中的值重新混合到SIMD寄存器并再次返回的唯一时间。否则,这是一个很少或没有实际好处的性能消耗。
你也可以在行动中看到这一点。看看输出什么样的变化只是扔-m32
开关:
Foo():
fldz
ret
FLDZ
是在浮点堆栈的顶部,在那里它已准备好要返回到装载恒为零的x87 FPU指令呼叫者,召集者。显然,当你让代码更复杂时,你更可能改变优化器的启发式并且说服它发出SIMD指令。如果您启用基于矢量化的优化,则您更有可能仍然是。
嗨科迪格雷,谢谢你的回复。还有一个问题需要跟进。在使用fastmath进行编译时,由于这些vex前缀说明,我看到了一个很大的加速。你知道这些vex-prefix指令如何比原来的x87指令表现得更好吗?谢谢 – PST
@PST好的,常规的SSE指令往往比x87指令更快。这有多个复杂的原因。其中最重要的一点是x87 FPU可以在基于堆栈的系统中运行,并具有所有伴随的限制,而SSE实施使用寄存器。这意味着没有时间浪费在堆栈上压入/弹出值,或者在堆栈的不同位置交换值。 SSE比x87更快的另一个原因仅仅是它是一个更新的实现,并且已经相应地进行了优化。 –
然后,我的回答已经解释了为什么以VEX为前缀的SSE指令比常规的SSE指令更快。因此,您将获得两项性能改进:首先从x87切换到SSE,然后从SSE切换到VEX编码的SSE。英特尔工程师必须在过去15 - 20年内达到某种程度。 :-) –
只需添加到Cody Gray's very good answer,您可以通过输出到汇编器并打开-fverbose-asm
来检查gcc的内部启用选项。
例如:
gcc -O2 -fverbose-asm -S -o test.S test.c
将列出test.S
在选定的优化级别(这里-O2
)启用所有的优化选项。
另请参阅http://gcc.godbolt.org/,您可以在其中看到编译器asm输出并消除了噪声。 –
- 1. 奇怪ngIf + $编译行为
- 2. Xcode6为iOS7编译的奇怪行为
- 3. 奇怪的编译器行为
- 4. 奇怪的编译器行为
- 5. 奇怪的编译器行为(C++)
- 6. 咖啡编译器的奇怪行为
- 7. 奇怪805的sdcc编译器行为
- 8. 奇怪的编译4.2
- 9. 奇怪的编译错误
- 10. 奇怪的编译器
- 11. 奇怪的CLR编译
- 12. 奇怪的django翻译行为
- 13. 奇怪CoreData编译错误
- 14. 代码编译奇怪
- 15. 奇怪的依赖行为VS.NET 2005(不必要的.CPP编译)
- 16. C++编译器中的奇怪行为 - 优化?
- 17. 奇怪的行为时,编译多控制器项目
- 18. 空数组声明 - 奇怪的编译器行为
- 19. 错误和奇怪的行为编译perl脚本
- 20. Flex编译 - 元数据标记的奇怪行为
- 21. gcc预编译头奇怪的行为与-c选项
- 22. 奇怪的编译器行为 - 可选参数
- 23. 奇怪的JDK行为是否应该编译?
- 24. 奇怪的C#编译器行为(重载)
- 25. 解释奇怪的Scala编译器行为
- 26. 编译器标志更改代码行为(O2,Ox)
- 27. 奇怪行为
- 28. 奇怪行为
- 29. 奇怪行为
- 30. 奇怪行为
通过一个具体的例子,你的问题会更容易回答。 –