【问题标题】:High Performance Bit Removal (XOR vs. subtract)高性能位删除(XOR 与减法)
【发布时间】:2021-07-25 14:29:48
【问题描述】:

据我了解,XOR 会影响分支预测。

对于将运行很多次的操作,最好通过减法还是通过异或来删除位?

// For an operation that will run several million times ...
int encoding = 180391281; // could be anything but we'll pick a number ...
#define REMOVE_BITS (128+64)

int bits_to_remove = encoding & REMOVE_BITS;
int encoding_with_bits_removed_xor_method      = encoding ^ /*XOR*/ bits_to_remove; // BEST?
int encoding_with_bits_removed_subtract_method = encoding - /*SUB*/ bits_to_remove; // BEST?

【问题讨论】:

  • 性能上不太可能有任何差异。这两个操作都映射到对 cpu 寄存器的简单操作
  • 启用优化的构建,并比较生成的汇编代码。
  • 但是异或和减法不是取消设置位的正确方法。使用否定掩码应用 ANDing。
  • 作为一些关于手动优化代码的一般提示:像这样的微优化几乎不值得。并且总是 进行基准测试和测量,以找出程序中最重要的两个 瓶颈,然后只将精力集中在这些部分上。最后,手动优化代码通常会使代码变得非常复杂,难以阅读、理解和维护,因此请始终包含大量关于代码的文档和 cmets,以及它为什么这样做。
  • @B.Nadolson "我的理解是 XOR 会影响分支预测。" 引用?

标签: c xor micro-optimization branch-prediction


【解决方案1】:

如果您深入研究数字电子电路;对于按位布尔运算(AND、OR、XOR、XNOR),每个位都可以并行完成,而对于加法/减法,它们不能是(最低位对的进位/借位会影响下一个最高位对的结果位,其中...)。

但是; CPU 很复杂,为了使所有部分保持同步,通常情况下(不包括极少见的异步/无时钟设计,如 GreenArrays 的芯片)都会四舍五入到最接近的时钟周期;因此,可以在 0.5 个周期内完成的 XOR 将花费 1 个完整周期,而可以在 0.9 个周期内完成的 SUB 将花费相同的 1 个完整周期。

换句话说;一般来说,XOR(或 AND)和 SUB 之间的性能差异极不可能(但我仍然更喜欢 XOR 或 AND,因为它“在理论上对 CPU 来说更简单”并且可能会稍微降低功耗)。

一个更重要的考虑因素(特别是对于高级语言,其中有一个应该为您进行微优化的编译器)是源代码的可读性。对于位删除,AND 是常见的做法,而 SUB 是不常见的(更容易让读者感到困惑)。如果 XOR 可以帮助您避免 NOT(例如 a = b ^ c 并不比 a = b & (~c) 更难理解),那么 XOR 是合理的;但是您可以颠倒术语(例如,将“要删除的位”替换为“位掩码”)并在没有 NOT 的情况下以 a = b & c 结尾,如果您可以这样做,它可能会提高可读性。

【讨论】:

  • 对于删除你已经知道设置为某个值的位,- 有优势:编译器可以使用lea reg, [reg - (128+64)] 复制和减去一个常量,如果它想保留原来的周围只是以不同的寄存器中的结果结束。此外,如果您想在结果为 0 或其他内容上进行分支,sub/jnz 可以 macro-fuse 进入 Intel 上的单个子分支 uop。 (但与 XOR 不同,AND 也可以)。 Fusion 是我对查询者可能与“分支预测”混淆的唯一猜测。
猜你喜欢
  • 2015-05-09
  • 2016-05-10
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 2012-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多