在x86彙編中將暫存器設定為零的最佳方法是什麼:xor,mov或?
在x86彙編中將暫存器設定為零的最佳方法是什麼:xor,mov或?
以下所有說明都做同樣的事情:設定%eax為零。哪種方式最佳(需要最少的機器週期)?
xorl %eax, %eax
mov $0, %eax
andl $0, %eax
TL; DR摘要:xor same, same是所有CPU的最佳選擇。沒有其他方法比它有任何優勢,它至少比任何其他方法都有一些優勢。它是由英特爾和AMD正式推薦的。在64位模式下,仍然使用xor r32, r32,因為寫32位暫存器會將上面的32復位。 xor r64, r64是浪費一個位元組,因為它需要一個REX字首。
更糟糕的是,Silvermont只承認xor r32,r32破壞而不是64位運算元。因此,即使因為你將r8…r15歸零而仍然需要REX字首,請使用xor r10d,r10d,而不是xor r10,r10。
例子:
xor eax, eax ; RAX = 0
xor r10d, r10d ; R10 = 0
xor edx, edx ; RDX = 0
; small code-size alternative: cdq ; zero RDX if EAX is already zero
; SUB-OPTIMAL
xor rax,rax ; waste of a REX prefix, and extra slow on Silvermont
mov eax, 0 ; doesn’t touch FLAGS, but not faster and takes more bytes
歸零向量暫存器通常最好用pxor xmm, xmm。這通常是gcc所做的(甚至在使用FP指令之前)。
xorps xmm, xmm可以有意義。它比一個位元組短一個位元組pxor,但xorps在Intel Nehalem上需要執行埠5,同時pxor可以在任何埠(0/1/5)上執行。(Nehalem在整數和FP之間的2c旁路延遲延遲通常是不相關的,因為無序執行通常可以在新的依賴鏈的開始處隱藏它)。
在SnB系列微體系結構中,xor-zeroing的味道都不需要執行埠。在AMD和預Nehalem的P6 / 2英特爾,xorps和pxor被處理的相同方式(如向量整數指令)。
使用AVX版本的128b向量指令也會將reg的上半部分vpxor xmm, xmm, xmm歸零,因此對於歸零YMM(AVX1 / AVX2)或ZMM(AVX512)或任何將來的向量擴充套件是一個很好的選擇。 vpxor ymm, ymm, ymm但是,不需要任何額外的位元組來編碼,並且執行相同。AVX512 ZMM歸零將需要額外的位元組(對於EVEX字首),因此應首選XMM或YMM歸零。
有些CPU認為sub same,same是類似的歸零xor,但所有識別任何歸零習慣用語的CPU都能識別xor。只需使用xor,您就不必擔心哪個CPU識別哪個歸零成語。
xor(作為公認的歸零成語,不像mov reg, 0)有一些明顯的和一些微妙的優點(摘要列表,然後我將擴充套件那些):
程式碼大小比mov reg,0。(所有CPU)
避免對以後的程式碼進行部分暫存器處罰。(英特爾P6系列和SnB系列)。
不使用執行單元,節省電力並釋放執行資源。(英特爾SnB系列)
較小的uop(沒有立即資料)在uop快取行中留出空間,以便在需要時附近的指令借用。(英特爾SnB系列)。
不會使用物理暫存器檔案中的條目。(英特爾SnB系列(和P4)至少可能是AMD,因為他們使用類似的PRF設計而不是像ROB P6系列微架構那樣在ROB中保持暫存器狀態。)
較小的機器程式碼大小(2個位元組而不是5個)始終是一個優勢:更高的程式碼密度導致更少的指令快取未命中,更好的指令獲取和潛在的解碼頻寬。
在Intel SnB系列微體系結構上不使用 xor 執行單元的好處很小,但節省了功耗。它更可能與SnB或IvB有關,它只有3個ALU執行埠。Haswell以及後來有4個執行埠可以處理整數ALU指令,包括mov r32, imm32,所以通過排程程式完美決策(實際上不會發生),HSW仍然可以維持每個時鐘4個uop,即使它們都需要執行埠。
有關更多詳細資訊,請參閱我關於歸零暫存器的另一個問題的答案。
Bruce Dawson的部落格帖子 Michael Petch連結(在對問題的評論中)指出xor在註冊重新命名階段處理而不需要執行單元(在未融合域中為零uops),但錯過了它仍然是一個uop的事實在融合域中。現代英特爾CPU可以每個時鐘發出和退出4個融合域uop。這就是每時鐘限制4個零的來源。暫存器重新命名硬體的複雜性增加只是將設計寬度限制為4的原因之一。(Bruce撰寫了一些非常優秀的部落格文章,比如關於FP數學和x87 / SSE /舍入問題的系列文章,我這樣做了極力推薦)。
在AMD Bulldozer系列CPU上,mov immediate執行在相同的EX0 / EX1整數執行埠上xor。mov reg,reg也可以在AGU0 / 1上執行,但這僅用於暫存器複製,而不是用於設定。所以,據我所知,在AMD公司唯一的優勢xor過分mov的是較短的編碼。它也可能節省物理暫存器資源,但我還沒有看到任何測試。
公認的歸零成語避免了對Intel CPU的部分暫存器處罰,後者將部分暫存器與完整暫存器(P6和SnB系列)分開重新命名。
xor將標記暫存器為具有上部歸零,所以xor eax, eax/ inc al/ inc eax避免了通常的區域性暫存器懲罰該IVB預CPU具有。即使沒有xor,當AH修改高8位()然後讀取整個暫存器時,IvB只需要合併uop ,而Haswell甚至會刪除它。
來自Agner Fog的微型指南,第98頁(Pentium M部分,後面的部分包括SnB參考):
處理器將自身的XOR識別為將其設定為零。暫存器中的特殊標記會記住暫存器的高位為零,因此EAX = AL。即使在迴圈中也會記住此標記:
; Example 7.9. Partial register problem avoided in loop
xor eax, eax
mov ecx, 100
LL:
mov al, [esi]
mov [edi], eax ; No extra uop
inc esi
add edi, 4
dec ecx
jnz LL
(來自第82頁):只要您沒有得到中斷,錯誤預測或其他序列化事件,處理器就會記住EAX的高24位為零。
該引導件的pg82還證實,mov reg, 0被未識別為歸零成語,至少在早期的設計P6像PIII或PM。如果他們花費電晶體在後來的CPU上檢測它,我會感到非常驚訝。
xor設定標誌,這意味著在測試條件時必須小心。由於setcc遺憾的是隻能使用8位目的地,因此您通常需要注意避免部分註冊處罰。
如果x86-64將一個被移除的操作碼(如AAM)重新用於16/32/64位setcc r/m,並且在r / m欄位的源暫存器3位欄位中編碼謂詞,那就太好了一些其他單運算元指令將它們用作操作碼位)。但他們沒有這樣做,無論如何這對x86-32沒有幫助。
理想情況下,您應該使用xor/ set flags setcc//讀取完整暫存器:
…
call some_func
xor ecx,ecx ; zero before the test
test eax,eax
setnz cl ; cl = (some_func() != 0)
add ebx, ecx ; no partial-register penalty here
這在所有CPU上都具有最佳效能(無停頓,合併uop或錯誤依賴)。
當你不想在標誌設定指令之前進行xor時,事情會變得更復雜。例如,你想在一個條件上分支,然後在同一個標誌的另一個條件下setcc。例如cmp/jle,sete您要麼沒有備用暫存器,要麼完全不使用xor未採用的程式碼路徑。
沒有公認的歸零成語不會影響標誌,因此最佳選擇取決於目標微體系結構。在Core2上,插入合併uop可能會導致2或3個週期停頓。它似乎在SnB上更便宜,但我並沒有花太多時間來測量。使用mov reg, 0/ setcc會對較舊的英特爾CPU造成重大損失,並且在較新的英特爾上仍然會有所改善。
如果你不能在標誌設定指令之前進行xor-zero,那麼使用setcc/ movzx r32, r8可能是Intel P6和SnB系列的最佳選擇。這應該比在xor-zeroing之後重複測試更好。(甚至不考慮sahf/ lahf或pushf/ popf)。IvB可以消除movzx r32, r8(即使用暫存器重新命名處理它,沒有執行單元或延遲,如xor-zeroing)。Haswell後來只消除了常規mov指令,所以movzx需要一個執行單元並且具有非零延遲,使得test / setcc/ movzx比xor/ test / 差setcc,但仍然至少和test / mov r,0/ 一樣好setcc(並且在舊CPU上要好得多)。
在AMD / P4 / Silvermont上使用setcc/ movzx沒有歸零是不好的,因為它們不會分別跟蹤子暫存器的deps。暫存器的舊值會有一個錯誤的缺陷。當/ test / 不是一個選項時,使用mov reg, 0/ setcc進行歸零/依賴性破壞可能是最好的選擇。xorsetcc
當然,如果您不需要setcc輸出寬於8位,則不需要將任何內容歸零。但是,如果選擇最近屬於長依賴關係鏈的暫存器,請注意除P6 / SnB之外的CPU的錯誤依賴性。(如果你呼叫一個可以儲存/恢復你正在使用的暫存器的函式,請注意引起部分註冊失效或額外的uop。)
and具有立即零並不是特殊的,與我所知的任何CPU上的舊值無關,因此它不會破壞依賴鏈。它沒有優點xor,也有許多缺點。
請參閱http://agner.org/optimize/獲取microarch文件,包括哪些歸零成語被識別為依賴性破壞(例如sub same,same,在某些但不是所有CPU上,而在所有CPU xor same,same上都被識別。) mov確實打破了舊值的依賴關係鏈暫存器(無論源值如何,零或不,因為這是mov有效的)。 xor只有在src和dest是同一個暫存器的特殊情況下才會斷開依賴鏈,這就是為什麼它被mov排除在特別識別的依賴斷層列表之外。(另外,因為它不被認為是歸零成語,具有其他好處。)
有趣的是,最古老的P6設計(PPro到Pentium III)並沒有認識到xor- 為了避免部分暫存器停頓而僅僅作為歸零用語,因此在某些情況下值得使用兩者。(參見Agner Fog的例子6.17。在他的microarch pdf中。他說這也適用於P2,P3,甚至(早期?)PM。 對連結部落格文章的評論說只有PPro有這種疏忽,但我’我們在Katmai PIII上進行了測試,並且@Fanael在Pentium M上進行了測試,我們都發現它沒有打破延遲限制imul鏈的依賴性。)
如果它確實使您的程式碼更好或儲存指令,那麼確保零,mov以避免觸控標誌,只要您不引入除程式碼大小之外的效能問題。但是,避免使用破壞標誌是不使用的唯一合理理由xor。
相關文章
- 什麼是庫存?什麼是零庫存?庫存的定義
- iOS彙編基礎(二)暫存器iOS
- 為什麼Modbus的只讀暫存器被稱為“輸入暫存器(Input Registers)”而不是“輸出暫存器”
- 重新整理彙編—————暫存器的基本概念[二]
- STM32暫存器的本質到底是什麼???
- 逆向學習筆記3——暫存器與彙編指令筆記
- 程式設計中暫存器的使用程式設計
- 靜態ip設定路由器的方法是什麼路由器
- 除錯時檢視彙編和暫存器資料等除錯
- 同樣是電晶體,為什麼暫存器比記憶體快呢?記憶體
- 【譯】為什麼ReasonReact是編寫React的最佳方式React
- 常用的x86彙編指令
- Java中將矩陣元素設定為零的三種演算法方法Java矩陣演算法
- mov格式用什麼軟體開啟 mov影片用什麼播放器開啟播放器
- CS 暫存器 和 IP 暫存器
- CPU 中通用暫存器的作用
- mov格式用什麼軟體開啟 mov視訊用什麼播放器開啟播放器
- 在Linux中,什麼是SAN和NAS儲存?Linux
- Java讀取暫存器資料的方法Java
- 關於STM32的BSRR(埠位設定/清除暫存器) 和 BRR(埠位清除暫存器) 的理解(初學32)
- 暫存器
- 在word中怎麼設定目錄 word設定目錄的方法
- SRAM是什麼儲存器
- 暫存器定址和暫存器間接定址的區別
- 為什麼 mov sp, 32,debug程式,執行sp=32的位置,後面的程式碼就全亂了(在小甲魚零基礎彙編第6章,包含多段程式,的影片程式碼)
- 在Java中建立物件的不同方法是什麼?Java物件
- 第五章:通用暫存器是()。
- 什麼是YottaChain儲存,為什麼說是未來資料儲存的趨勢?AI
- win10怎麼將potplayer設定為預設播放器_win10如何將potplayer設定為預設播放器Win10播放器
- 暫存器指定為寫0或者1
- Declaration vs. Definition of a variable in C(在c中,什麼是宣告什麼是定義)
- SciPy 最佳化器是什麼
- 為什麼說現在是投資加密貨幣的最佳時機加密
- PC暫存器
- 為什麼說儲存是區塊鏈最佳落地應用場景區塊鏈
- 什麼是計算機編碼的定義?計算機
- 瀏覽器中window.length的結果是什麼?為什麼?瀏覽器
- 為什麼VSCode是程式碼編輯器而不是IDE?VSCodeIDE