簡體   English   中英

使用bts匯編指令和gcc編譯器

[英]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的內存目標,或者使用ANDTestBit的內存源。 當然,如果你避免使用內聯asm,編譯器可以內聯TestBit並使用TEST而不是AND ,這在某些CPU上很有用(因為它可以在多於AND宏上融合到更多CPU上的測試和分支)。

這實際上是gcc 5.2從你的C源 (memory-dest ORTEST )生成的。 看起來對我來說是最優的(uop比memory-dest bt )。 實際上,請注意您的代碼被破壞,因為它假設unsigned long是32位,而不是CHAR_BIT * sizeof(unsigned_long) 使用uint32_tchar ,將是一個更好的計划。 請注意使用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));
}

另一個稍微間接的答案是,GCC公開從4.1版本開始的一些原子操作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM