回答
你可以試試這個自己看到了答案:
movl $0,%eax
xor %eax,%eax
總合,然後拆卸:
as xor.s -o xor.o
objdump -D xor.o
並獲得
0: b8 00 00 00 00 mov $0x0,%eax
5: 31 c0 xor %eax,%eax
爲32位寄存器的MOV指令2.5倍大,需要更長的時間從RAM加載並消耗更多的緩存空間。早在一天僅加載時間是一個殺手,今天的存儲週期時間和緩存空間可以說是沒有那麼明顯,但如果你的編譯器和/或代碼,這是否過於頻繁,你會看到緩存的損失空間和/或更多的驅逐,以及更慢的系統內存週期。
在現代的CPU,更大的代碼大小還可以減慢解碼器,可能阻止他們的解碼每一週期的x86指令最大數量。 (例如,對於某些CPU,在一個16B塊中最多有4條指令)。
也有performance advantages to xor over mov in some x86 CPUs (especially Intel's) that have nothing to do with code-size,所以xor-zeroing在x86程序集中總是首選。
另一組實驗:
void fun1 (unsigned int *a)
{
*a=0;
}
unsigned int fun2 (unsigned int *a, unsigned int *b)
{
return(*a^*b);
}
unsigned int fun3 (unsigned int a, unsigned int b)
{
return(a^b);
}
0000000000000000 <fun1>:
0: c7 07 00 00 00 00 movl $0x0,(%rdi)
6: c3 retq
7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
e: 00 00
0000000000000010 <fun2>:
10: 8b 06 mov (%rsi),%eax
12: 33 07 xor (%rdi),%eax
14: c3 retq
15: 66 66 2e 0f 1f 84 00 nopw %cs:0x0(%rax,%rax,1)
1c: 00 00 00 00
0000000000000020 <fun3>:
20: 89 f0 mov %esi,%eax
22: 31 f8 xor %edi,%eax
24: c3 retq
低頭出什麼變量異或我,我在你的問題可能導致的路徑。既然你沒有指定你指的是哪個處理器或什麼上下文,就很難畫出整個圖片。例如,如果你在談論C代碼,你要明白做的代碼什麼的編譯器,這在很大程度上取決於在函數中的代碼,如果你的異時,編譯器在寄存器中,並根據操作數在你的編譯器設置上,你可能會得到xor eax,eax。或者編譯器可以選擇將其更改爲mov reg,0或更改something = 0;到一個xor reg,reg。
有些多個序列來思考:
如果地址變量已經在寄存器:
7: c7 07 00 00 00 00 movl $0x0,(%rdi)
d: 8b 07 mov (%rdi),%eax
f: 31 c0 xor %eax,%eax
11: 89 07 mov %eax,(%rdi)
編譯器會選擇MOV零,而不是XOR。如果你試過這個C代碼,你會得到什麼結果:
void funx (unsigned int *a)
{
*a=*a^*a;
}
編譯器用移動零代替它。獲取的字節數相同,但需要訪問兩個存儲器而不是一個存儲器,並註冊一個寄存器。並執行三條指令而不是一條。所以移動零點明顯更好。現在
如果是字節大小,並在寄存器:
13: b0 00 mov $0x0,%al
15: 30 c0 xor %al,%al
代碼大小沒有區別。 (但他們仍然執行不同)。
現在,如果你在談論另一個處理器,可以說ARM
0: e3a00000 mov r0, #0
4: e0200000 eor r0, r0, r0
8: e3a00000 mov r0, #0
c: e5810000 str r0, [r1]
10: e5910000 ldr r0, [r1]
14: e0200000 eor r0, r0, r0
18: e5810000 str r0, [r1]
你不使用XOR(異或,EOR)保存任何東西:一個指令一個指令都取和執行。如果你有一個寄存器中的變量地址,就像任何處理器一樣,在ram中着色。如果您必須將數據複製到另一個寄存器來執行異或操作,那麼您仍然會得到兩次內存訪問和三條指令。如果您的處理器可以將內存寫入內存,則零移動更便宜,因爲您只有一個內存訪問權限和一個或兩個指令,具體取決於處理器。
實際上它比這更糟:eor r0, r0, r0
是required to have an input dependency on r0
(限制無序執行),因爲內存排序規則。 Xor-zeroing總是會產生零,但只會幫助x86彙編的性能。
因此,底線是要看,如果你是在彙編在x86系統上的任何地方,從8088交談寄存器到現在的XOR通常更快,因爲指令更小,讀取速度更快,佔用較少的緩存,如果您有一個,爲其他代碼留下更多緩存等。同樣,非x86可變指令長度處理器要求在指令中編碼爲0,也需要更長的指令,更長的獲取時間,如果存在高速緩存等等。所以xor更快(通常取決於它如何編碼)。如果你有條件標誌並且你想要移動/ xor設置零標誌,它會變得更糟,你可能不得不刻錄正確的指令(在某些處理器上mov不會改變標誌)。有些處理器有一個特殊的零寄存器,這是不通用的,當你使用它時,你得到一個零,你可以編碼這個非常常見的用例,而不用燒更多的指令空間或燒製一個額外的指令週期,將零立即加載到寄存器。例如,msp430,0x1234的移動會花費你一個兩字的指令,但移動0x0000或0x0001和一些其他常量可以編碼在一個指令字中。如果你正在討論RAM中的變量,讀 - 修改 - 寫兩個內存週期而不計算指令讀取次數,則所有處理器將對內存產生雙重打擊,並且如果讀取導致緩存行填充,寫入會變得更糟非常快),但是如果沒有讀取,寫入只能通過緩存並且執行速度非常快,因爲處理器可以在寫入並行進行時保持運行(有時您會獲得性能增益,有時候不會,如果您調整爲了它)。 x86和可能較舊的處理器是您看到xoring而不是移動零的習慣的原因。對於那些特定的優化,性能增益仍然存在,系統內存仍然非常緩慢,任何額外的內存週期都是昂貴的,同樣,任何被拋棄的緩存都是昂貴的。中途體面的編譯器甚至gcc會檢測出xor i,我相當於i = 0,並且根據個案情況選擇更好的(在平均系統上)指令序列。
獲得大會由邁克爾·亞伯拉什禪宗的副本。好的,使用的副本可以以合理的價格(低於50美元)獲得,即使您購買了80美元的副本,也是非常值得的。試着超越特定的8088「自行車愛好者」,並瞭解他正在嘗試教授的一般思維過程。然後花費盡可能多的時間來拆卸代碼,理想的情況是適用於許多不同的處理器。應用您學到了什麼?
優秀的答案! – stdcall
然而,在過去的CPU上(但是在Pentium Pro之後,根據註釋),現在的大多數現代CPU都有特殊的熱路徑,用於零分配(寄存器和完全對齊的變量)應該產生相同的性能。大多數現代編譯器都傾向於混合使用這兩種編譯器(具體取決於周圍的代碼)(較早的MSVC編譯器在優化版本中始終使用XOR
,並且在某些情況下仍會使用XOR
,但也會使用)。
這是一個非常微觀的優化,所以tbh,你可以做任何你最好的套件,除非你有嚴格的循環由於寄存器依賴性而滯後。但應該注意的是,使用XOR
大部分時間佔用較少的空間,這對於嵌入式設備或者嘗試對齊分支目標時非常有用。
這裏假定您主要是指x86及其衍生產品,那麼@Pascal給了我一個想法,即爲此提供技術參考。英特爾優化手冊分爲兩部分,即2.1.3.1 Dependancy Breaking Idioms
和3.5.1.7 Clearing Registers and Dependancy Breaking Idioms
。這兩個部分基本支持使用基於XOR
的指令進行任何形式的寄存器清除,因爲它具有依賴性斷開特性(消除延遲)。但是在條件代碼需要保存的部分,最好將0寫入寄存器。
我有** no **想法你的意思是「零分配的熱路徑」。你能提供一個參考嗎?另一方面,'xor reg,reg'比Pentium Pro上的'mov reg,0'慢,因爲處理器認爲前者依賴於reg。在此之前,在這個處理器系列中沒有亂序執行,並且在那之後,處理器學會識別'xor reg,reg'獨立於'reg'的前一個值。 –
@Pascal:通過「零分配熱路徑」我的意思是,微代碼優化,最小的延遲要做到這一點(由你提分手的依賴關係) – Necrolis
在SandyBridge的,XOR歸零是特例,並辦理登記重命名,它甚至不使用執行端口。我從來沒有聽說過類似的技巧適用於'mov reg,0',但是如果它們存在,它會很酷,你有一個來源嗎? – harold
當然由於XOR指令長度較短,預取隊列內存帶寬限制是在8088真(以及在較小程度8086)。
- 1. 與模板相比,組件是否真的更快?
- 2. 計算xor爲零的整數分區
- 3. 對於已更改的文件,rsync是否真的更快?
- 4. 是布爾還是零比較更快?
- 5. 分配+零個
- 6. 2-Satisfiability問題 - 是否存在唯一的真值分配
- 7. NSString分配與否!
- 8. FlatBuffer的零分配是Java實現嗎?
- 9. 在XOR中獨佔是否真的適用於兩個以上的輸入?
- 10. ELF .notes部分是否真的需要?
- 11. 鎖是否分配
- 12. Mathematica:零件分配
- 13. Calloc()不分配零
- 14. 與非零分母除分子總是給人在C#零
- 15. 分配值僅如果不是零
- 16. 與默認4KB相比,16KB或32KB的NTFS分配塊是否會使編譯時間更快?
- 17. 是否可以使用XOR來檢測多個條件中的一個是否爲真?
- 18. 哪個更快:計算或分配
- 19. lambda微積分xor表達式通過真假
- 20. 是否stream.max()總是比stream.reduce()更快?
- 21. 全局分區索引是否比非分區索引更好(更快)?
- 22. 是否有更快的方式REGEX SortedList?
- 23. matlab中的快速xor數組
- 24. 檢查內存是否歸零的最快方法
- 25. 檢查Swift中的Firebase快照是否等於零
- 26. IQueryable與IEnumerable:IQueryable總是更好更快?
- 27. NginX是否適合論壇? NginX真的很快嗎?
- 28. StringBuilder真的比Aggreggate更快嗎?
- 29. 在JVM上PHP真的更快嗎?
- 30. 是++我真的比i ++中的for循環更快嗎?
的可能重複[使用是否XOR章,章給優勢MOV REG,0?(http://stackoverflow.com/questions/1135679/does-using-xor-reg-reg-give-advantage-over -mov-REG-0) –
['XOR EAX,eax'是零在86 ASM的寄存器(由於許多原因,不只是代碼尺寸)的最佳方式](http://stackoverflow.com/questions/33666617 /什麼是最好的方式來設置一個寄存器到零 - 在x86-assembly-xor-mov-or-and),但在C源代碼中,你應該總是寫'var = 0;'讓編譯器爲你使用xor。不要寫'var^= var',因爲它具有零優勢和許多可能的缺點(例如擊敗優化器,特別是如果var未初始化)。只發布評論,因爲這個問題似乎困惑於關於ASM與編譯器輸入的問題。 –