我正在尋找一種最快/最節省空間的方法,將一個64位暫存器減少到32位暫存器,只保留64位暫存器的零/非零狀態。
例如:
//rax為零或非零
popcntq %rax, %rax
// 如果rax為零,eax將為零,否則將為非零。
注意:直接使用32位的 目前,我被困在尋找比 是否有一些更好的聰明方法? 編輯:洗掉了編輯內容。
編輯:洗掉了編輯內容,因為它們對問題沒有任何幫助。
uj5u.com熱心網友回復: 一個選項是 記住, 仍然是 5 個位元組,2 個 uops,而不是 1 個。但是如果我的計算是正確的,在 Skylake 上,你得到的是 2 個周期的延遲,而不是 3 個周期,每個周期的吞吐量是 2,而不是 1。
uj5u.com熱心網友回復:eax是行不通的,如果rax是2^61,那么eax的零/非零狀態與rax不一樣。
popcntq(1c tput, 3c latency, 5 byte code size)更好的東西,對所有的值都有效。neg rax ; 48 F7 D8
sbb eax, eax; 19 C0
neg設定標志就像從零減去一樣,所以如果rax非零,它就會設定攜帶標志。 暫存器的sbb從其本身產生0或-1,這取決于進位是否被清除或設定(感謝@prl在評論中建議)。
也是最小的代碼大小,5個位元組。
popcnt %rax, %rax # 5位元組,一個埠的1個uop
在大多數有這個功能的CPU上,它的延遲為3c,吞吐量為1c(一個埠為1個uop)。 或者在Zen1/2/3上為1c,延遲為0.25c。 (https://agner.org/optimize/)
在Excavator之前的Bulldozer-family上,popcnt r64是4c延遲,4c吞吐量。 (32 位運算元有 2c 吞吐量,但仍有 4c 延遲。) Bobcat 有相當慢的微編碼 popcnt。
最低延遲
最低延遲(假設 Haswell 或更新版本,因此在寫入 AL 和讀取 EAX 時沒有部分暫存器的影響,或者沒有 P6 祖先的 uarch 不會重命名部分暫存器): 2個周期的延遲,2個uops,6個位元組。
Nate的neg/sbb在Broadwell和更高版本上與這個差不多,但短了1個位元組
。
測驗 %rax, %rax # 3B, 1 uop any ALU port
setnz %al # 3B, 1 uop p06 (Haswell ... Ice Lake)
AL是EAX的低位元組,所以AL=1肯定會使EAX對于任何非零的RAX都是非零的。
在 Sandybridge/Ivy Bridge 上讀取 EAX 時,這將花費一個合并的 uop。 Core2/Nehalem將停滯幾個周期以插入該合并uop。 早期的P6家庭,如Pentium-M,將完全停滯,直到setcc退休,如果一個后來的指令讀取EAX。 (為什么GCC不使用部分暫存器?)
如果你想把上面的32個暫存器清零,BMI2 RORX來復制和移位:
2 uops, 2c latency, 8 bytes
rorx $32, %rax, %rdx # 6 bytes, 1 uop, 1c latency
或者
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/331320.html
標籤:
