[英]Verifying compiler optimizations in gcc/g++ by analyzing assembly listings
[英]Using bts assembly instruction with gcc compiler
我想使用bts和bt x86匯編指令來加速Mac上C ++代碼中的位操作。 在Windows上,_bittestandset和_bittest內在函數運行良好,並提供顯着的性能提升。 在Mac上,gcc編譯器似乎不支持這些,所以我試圖直接在匯編程序中執行它。
這是我的C ++代碼(注意'bit'可以> = 32):
typedef unsigned long LongWord;
#define DivLongWord(w) ((unsigned)w >> 5)
#define ModLongWord(w) ((unsigned)w & (32-1))
inline void SetBit(LongWord array[], const int bit)
{
array[DivLongWord(bit)] |= 1 << ModLongWord(bit);
}
inline bool TestBit(const LongWord array[], const int bit)
{
return (array[DivLongWord(bit)] & (1 << ModLongWord(bit))) != 0;
}
以下匯編程序代碼可以工作,但不是最優的,因為編譯器無法優化寄存器分配:
inline void SetBit(LongWord* array, const int bit)
{
__asm {
mov eax, bit
mov ecx, array
bts [ecx], eax
}
}
問題:如何使編譯器完全優化bts指令? 如何用bt指令替換TestBit?
具有存儲器目的地的BTS
(和其他BT*
insn) 很慢。 (英特爾> 10 uops) 。 你可能會從地址數學中獲得更快的代碼來找到正確的字節,並將其加載到寄存器中。 然后,您可以使用注冊目的地執行BT
/ BTS
並存儲結果。
或者可以將1
移位到正確的位置並使用OR
與SetBit的內存目標,或者使用AND
與TestBit
的內存源。 當然,如果你避免使用內聯asm,編譯器可以內聯TestBit
並使用TEST
而不是AND
,這在某些CPU上很有用(因為它可以在多於AND
宏上融合到更多CPU上的測試和分支)。
這實際上是gcc 5.2從你的C源 (memory-dest OR
或TEST
)生成的。 看起來對我來說是最優的(uop比memory-dest bt
)。 實際上,請注意您的代碼被破壞,因為它假設unsigned long
是32位,而不是CHAR_BIT * sizeof(unsigned_long)
。 使用uint32_t
或char
,將是一個更好的計划。 請注意使用cqde
指令將eax
符號擴展到rax
,因為編寫錯誤的C使用1
而不是1UL
。
另請注意,內聯asm不能返回結果標志(除了使用new-in-gcc v6擴展名! ),因此對TestBit使用內聯asm可能會導致可怕的代碼如下:
... ; inline asm
bt reg, reg
setc al ; end of inline asm
test al, al ; compiler-generated
jz bit_was_zero
現代編譯器可以並且確實在適當時使用BT
(具有寄存器目的地)。 最終結果:您的C可能編譯為比您建議使用內聯asm更快的代碼。 在被修復為正確且64位清潔之后它會更快。 如果你正在優化代碼大小,並願意支付顯着的速度懲罰,強制使用bts
可能會有效,但bt
可能仍然無法正常工作(因為結果會進入標志)。
inline void SetBit(*array, bit) {
asm("bts %1,%0" : "+m" (*array) : "r" (bit));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.