我正在編譯使用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. 奇怪行爲
通過一個具體的例子,你的問題會更容易回答。 –