位算子,而不是在分支中使用XOR

Bitwise operators, not vs xor use in branching

本文关键字:分支 XOR      更新时间:2023-10-16

在问这个问题之后,我收到了 @andonm.coleman的一条非常有趣的评论,我必须验证。

由于您的拆卸代码是为X86编写的,因此值得指出的是,XOR会设置/清除零标志,而不会(如果您想在不影响依赖于从中依靠标志的跳跃条件的位置操作)执行位置操作的情况下,则没有用以前的操作)。现在,考虑到您不是直接编写组件,您确实无法以有意义的方式访问此标志,所以我怀疑这是一个偏爱另一个标志的原因。

他的评论让我好奇以下代码是否会产生相同的大会说明

#include <iostream>
int main()
{
    unsigned int val = 0;
    std::cout << "Enter a numeric value: ";
    std::cin >> val;
    if ( (val ^ ~0U) == 0)
    {
        std::cout << "Value inverted is zero" << std::endl;
    } else
    {
        std::cout << "Value inverted is not zero" << std::endl;
    }
    if ( (~val) == 0)
    {
        std::cout << "Value inverted is zero" << std::endl;
    } else
    {
        std::cout << "Value inverted is not zero" << std::endl;
    }
    return 0;
}

以下两个操作

if ( (val ^ ~0U) == 0 )

if ( (~val) == 0 )

未在Visual Studio 2010中进行优化提供以下拆卸:

    if ( (val ^ ~0U) == 0)
00AD1501  mov         eax,dword ptr [val]  
00AD1504  xor         eax,0FFFFFFFFh  
00AD1507  jne         main+86h (0AD1536h)  

    if ( (~val) == 0)
00AD1561  mov         eax,dword ptr [val]  
00AD1564  not         eax  
00AD1566  test        eax,eax  
00AD1568  jne         main+0E7h (0AD1597h)  

我的问题涉及优化。写

更好
if ( (val ^ ~0U) == 0)

if ( (~val) == 0)

这取决于很多事情,但主要是(如果有的话),请告诉编译器以优化。

如果将编译器设置为优化大小(最小的字节码),则有时会在看似奇怪的地方使用XOR。例如,可变长度编码方案x86使用可以通过 XOR'以少于MOV指令所需的代码字节来将寄存器设置为 0

考虑使用XOR

的代码
if ( (val ^ ~0U) == 0 )  /* 3-bytes to negate and test (x86) */

&nbsp;&nbsp;&nbsp;&nbsp; XOR eax,0FFFFFFFFh需要3个bytes sets/sets/clear零标志(zf)

现在,考虑使用NOT的代码:

if ( (~val) == 0)        /* 4-bytes to negate and test (x86) */

&nbsp;&nbsp;&nbsp;&nbsp;NOT eax编码为2字节说明,但不影响CPU标志。

&nbsp;&nbsp;&nbsp;&nbsp;TEST eax,eax添加了额外的2个字节,并且需要设置/清除零标志(ZF)

是必要的

NOT也是一个简单的指令,但是由于它不会影响任何CPU标志,因此您必须在代码中看到的TEST指令以将其用于分支。这实际上会产生较大的字体模式,因此可以优化大小的智能编译器可能会可能尝试避免使用NOT。在CPU生成之间,这两个指令共同完成了多少个周期,而智能编译器也会将其纳入其决策中以优化速度。


如果您不编写手工调整的组件,最好使用对人类最清晰的任何内容,并希望编译器足够聪明,可以选择不同的说明/调度/调度。根据需要在编译时优化尺寸/速度。编译器具有用于选择和安排说明的智能启发式方法,他们对目标CPU架构的了解更多,而不是普通编码器。

稍后您发现该分支确实是一个瓶颈,并且在问题上没有更高级别的方法,那么您可以进行一些低级调整。但是,除非您针对低功率嵌入式CPU或内存有限的设备之类的东西,否则这几天要专注于这些天是如此微不足道的事情。我曾经曾经通过手动调整挤出足够的表现,以使其值得,这是在算法中受益于数据并行性的算法,并且编译器不够聪明,无法有效利用MMX/SSE等专业指导集。

<</p> <</p> <</p>