例如有了這樣的功能,
int fb(char a, char b, char c, char d) {
return (a b) - (c d);
}
gcc的匯編輸出是,
fb:
movsx esi, sil
movsx edi, dil
movsx ecx, cl
movsx edx, dl
add edi, esi
add edx, ecx
mov eax, edi
sub eax, edx
ret
含糊地,我明白 的目的movsx是從暫存器的先前值中洗掉依賴關系,但老實說,我仍然不明白它試圖洗掉什么樣的依賴關系。我的意思是,例如,是否存在movsx esi, sil,如果正在寫入某個值esi,則使用的任何操作esi都必須等待,如果正在從 讀取值esi,則任何修改 的值的操作esi都必須等待,如果esi沒有被任何操作使用,代碼將繼續運行。有什么區別movsx?我不能說編譯器做錯了,因為movsx或者movzx(幾乎?)在加載小于 32 位的值時總是由任何編譯器生成。
除了我缺乏理解之外,與s 的gcc行為不同。float
float ff(float a, float b, float c, float d) {
return (a b) - (c d);
}
編譯為,
ff:
addss xmm0, xmm1
addss xmm2, xmm3
subss xmm0, xmm2
ret
如果應用相同的邏輯,我相信輸出應該是這樣的,
ff:
movd xmm0, xmm0
movd xmm1, xmm1
movd xmm2, xmm2
movd xmm3, xmm3
addss xmm0, xmm1
addss xmm2, xmm3
subss xmm0, xmm2
ret
所以我實際上是在問兩個問題。
- 為什么
gcc與 s 的行為不同float? - 有什么區別
movsx?
uj5u.com熱心網友回復:
回傳值與 args 的寬度相同,因此不需要擴展。在 x86 和 x86-64 呼叫約定中,允許型別寬度之外的暫存器部分保存垃圾。(這適用于 GP 整數和向量暫存器。)
除了 clang 依賴的未記錄擴展,呼叫者將窄 args 擴展到 32 位;clang 將跳過
movsx您char示例中的說明。 https://godbolt.org/z/Gv5e4h3Eh向 x86-64 ABI 的指標添加 32 位偏移時是否需要符號或零擴展?涵蓋了高垃圾和呼叫約定的非官方擴展。
由于您詢問了錯誤依賴項,請注意編譯器確實用于
movaps xmm,xmm復制標量。(例如,在 GCC 錯過的優化中,(a-b) (a-d)我們需要從a兩次中減去。它是不可交換的,所以我們需要一個副本:https
://godbolt.org/z/Tvx19raa3 確實,movss xmm1, xmm0它依賴于 XMM1 而movaps沒有,它會如果您實際上并不關心與舊的高位元組合并,則成為錯誤的依賴項。(對 Pentium III 或 Pentium M 進行調整可能是有意義的,
movss因為它在那里是單微指令,但當前的 GCC-O3 -m32 -mtune=pentium3 -mfpmath=sse使用 movaps,花費第二個微指令以避免錯誤的依賴。直到 Core2 才將 SIMD 執行單元擴大到P6 系列為 128 位,匹配 Pentium 4。)C 整數提升規則意味著
a b對于窄輸入等價于(int)a (int)b. 在所有 x86 / x86-64 ABI 中,char是有符號型別(例如,與 ARM 不同),因此需要將其符號擴展為int寬度,而不是零擴展。并且絕對不會被截斷。如果您通過回傳 a 再次截斷結果
char,編譯器可以只做 8 位加法。但實際上他們將使用 32 位添加并在那里留下任何高垃圾:https ://godbolt.org/z/hGdbecPqv 。這樣做不是為了破壞/性能,只是為了正確。char就性能而言,如果呼叫者撰寫了完整的暫存器(呼叫約定的非官方擴展無論如何都需要),或者在不單獨重命名低 8 位的 CPU 上,GCC 為 a 讀取 32 位 reg 的行為很好。 reg 的其余部分(除了 P6-family: SnB-family 僅重命名高 8 regs,除了原始的 Sandybridge 本身。 為什么 GCC 不使用部分暫存器?)
PS:沒有這樣的指令movd xmm0, xmm0,只有一種不同的形式,movq xmm0, xmm0其中 yes 會將 XMM 暫存器的低 64 位零擴展為完整的暫存器。
如果您想查看各種編譯器嘗試對低位 dword 進行零擴展,無論是否使用 SSE4.1 insertps,請查看__m128 foo(float f) { return _mm_set_ss(f); }上面 Godbolt 鏈接中的 asm。例如,僅使用 SSE2,使用 pxor 將暫存器歸零,然后movss xmm1, xmm0. 否則,insertps或異或零和blendps。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/415414.html
標籤:
下一篇:NASM中的MOVZBQ等價物
