c++ - 在 gcc 编译器中使用 bts 汇编指令

标签 c++ performance macos gcc assembly

我想使用 bts 和 bt x86 汇编指令来加速我在 Mac 上的 C++ 代码中的位操作。在 Windows 上,_bittestandset 和 _bittest 内部函数运行良好,并提供显着的性能提升。在 Mac 上,gcc 编译器似乎不支持这些,所以我尝试直接在汇编程序中进行。

这是我的 C++ 代码(请注意,“位”可以 >= 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* insns)具有内存目标 are slow. (>10 uops on Intel) .您可能会通过地址数学计算找到正确的字节并将其加载到寄存器中来获得更快的代码。然后你可以做 BT/BTS与注册目的地和存储结果。

或者转移一个1到正确的位置并使用OR带有 SetBit 的内存目标,或 AND带有 TestBit 的内存源.当然,如果你避免内联 asm,编译器可以内联 TestBit并使用 TEST而不是 AND ,这在某些 CPU 上很有用(因为它可以在比 AND 更多的 CPU 上宏融合到测试和分支中)。

This is in fact what gcc 5.2 generates from your C source (内存目标 ORTEST )。对我来说看起来是最佳的(比 memory-dest bt 更少的微指令)。实际上,请注意您的代码已损坏,因为它假定 unsigned long是 32 位,不是 CHAR_BIT * sizeof(unsigned_long) .使用 uint32_t , 或 char ,将是一个更好的计划。注意 eax 的符号扩展进入raxcqde指令,由于使用 1 的 C 写得不好而不是 1UL .

另请注意,内联 asm 无法返回标志作为结果(new-in-gcc v6 extension! 除外),因此将内联 asm 用于 TestBit 可能会导致糟糕的代码,例如:

...  ; 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可能仍然无法正常工作(因为结果进入标志)。

关于c++ - 在 gcc 编译器中使用 bts 汇编指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1983303/

相关文章:

iphone - 使用 SQLite 后端修复谓词 NSFetchedResultsController/NSFetchRequest 性能?

python - Python 中标记化数据的有效数据结构是什么?

swift - 访问非空变量时出现 EXC_BAD_ACCESS 异常

c++ - 相互引用的C++模板实例化

c++ - 使用 token 仅解析 csv 文件中的特定列

c++ - 如何为类的每个方法添加计时器?

c++ - 获取 "vector subscript out of range"错误

c# - 我的数据库连接关闭了吗? (Linq to Sql)

macos - 主 NSWindow 阴影不会像子窗口那样改变

swift - cocoa swift : Launch At Login not working & throws error in Xcode?