C++ 如果相等,则将无符号中的所有位设置为1,如果不相等,则设置为0

C++ 如果相等,则将无符号中的所有位设置为1,如果不相等,则设置为0,c++,C++,如何在不进行分支或条件移动的情况下,以最少的英特尔指令数实现以下目标: unsigned compare(unsigned x ,unsigned y) { return (x == y)? ~0 : 0; } 这是热门的代码路径,我需要挤出最多>返回-Itx==y是非常简洁的C++。当然,要将其转化为高效的程序集,还得由编译器来决定 Work:Intrue= 1,un签署- 1==0u.< /p>返回-iTx==y相当简洁C++。当然,要将其转化为高效的程序集,还得由编译器来决

如何在不进行分支或条件移动的情况下,以最少的英特尔指令数实现以下目标:

unsigned compare(unsigned x
  ,unsigned y) {
    return (x == y)? ~0 : 0;
}
这是热门的代码路径,我需要挤出最多

>返回-Itx==y是非常简洁的C++。当然,要将其转化为高效的程序集,还得由编译器来决定

Work:Intrue= 1,un签署- 1==0u.< /p>返回-iTx==y相当简洁C++。当然,要将其转化为高效的程序集,还得由编译器来决定


之所以有效,是因为inttrue==1和unsigned-1==0U。

GCC很好地解决了这一问题,并且它知道在使用-O2和更高版本编译时的求反技巧:

unsigned compare(unsigned x, unsigned y) {
    return (x == y)? ~0 : 0;
}

unsigned compare2(unsigned x, unsigned y) {
    return -static_cast<unsigned>(x == y);
}

compare(unsigned int, unsigned int):
        xor     eax, eax
        cmp     edi, esi
        sete    al
        neg     eax
        ret
compare2(unsigned int, unsigned int):
        xor     eax, eax
        cmp     edi, esi
        sete    al
        neg     eax
        ret
在这里,第一个版本似乎避免了有条件的移动,注意功能的顺序被改变了

要查看其他编译器的解决方案,请尝试将代码粘贴到 添加优化标志

有趣的是,第一个版本在icc上生成了更短的代码。基本上,您必须测量每个版本的编译器的实际性能,并选择最佳版本

此外,我也不确定有条件寄存器的移动是否比其他操作慢

我假设您编写该函数只是为了向我们展示代码的相关部分,但是像这样的函数将是内联的理想候选函数,它可能允许编译器执行更有用的优化,这些优化涉及实际使用的代码。这可能允许编译器/CPU将此计算与其他代码并行,或合并某些操作


因此,假设这确实是代码中的一个函数,用inline关键字编写它,并将它放在一个标题中。

GCC很好地解决了这一问题,并且它知道在使用-O2和更高版本编译时的否定技巧:

unsigned compare(unsigned x, unsigned y) {
    return (x == y)? ~0 : 0;
}

unsigned compare2(unsigned x, unsigned y) {
    return -static_cast<unsigned>(x == y);
}

compare(unsigned int, unsigned int):
        xor     eax, eax
        cmp     edi, esi
        sete    al
        neg     eax
        ret
compare2(unsigned int, unsigned int):
        xor     eax, eax
        cmp     edi, esi
        sete    al
        neg     eax
        ret
在这里,第一个版本似乎避免了有条件的移动,注意功能的顺序被改变了

要查看其他编译器的解决方案,请尝试将代码粘贴到 添加优化标志

有趣的是,第一个版本在icc上生成了更短的代码。基本上,您必须测量每个版本的编译器的实际性能,并选择最佳版本

此外,我也不确定有条件寄存器的移动是否比其他操作慢

我假设您编写该函数只是为了向我们展示代码的相关部分,但是像这样的函数将是内联的理想候选函数,它可能允许编译器执行更有用的优化,这些优化涉及实际使用的代码。这可能允许编译器/CPU将此计算与其他代码并行,或合并某些操作


因此,假设这确实是代码中的一个函数,用inline关键字编写它,并将它放在一个标题中。

我猜,x==y~0:0相当快。x==y*~0可能更快,也可能更快。但是,您应该在您的平台上尝试这一点,或者根据生成的汇编代码进行猜测。为什么不使用bool而使用unsigned?我的意思是,为了提高效率,我首先要消除最明显的冗余,即存储多个1/0,而一个1/0就足够了。值得一提的是,如果位级优化是一个问题,为什么要取消签名?因为我需要比较的结果作为另一个操作的位掩码。请注意,您可能希望使用~0U:0U来确保具有正确的位数-对于int可能不太担心,但是如果您更改为long,例如,这可能是一个问题。我想,x==y~0:0相当快。x==y*~0可能更快,也可能更快。但是,您应该在您的平台上尝试这一点,或者根据生成的汇编代码进行猜测。为什么不使用bool而使用unsigned?我的意思是,为了提高效率,我首先要消除最明显的冗余,即存储多个1/0,而一个1/0就足够了。值得一提的是,如果位级优化是一个问题,为什么要取消签名?因为我需要比较的结果作为另一个操作的位掩码。请注意,您可能希望使用~0U:0U以确保具有正确的位数-可能不太担心int,但是如果您要更改为long,例如,这可能是一个问题。该函数实际上是更大框架的一部分,并且标记为内联。我想知道BMI2指令集是否允许更短的版本?我正在使用的clang 4.0也会生成一个cmov版本。该函数确实是更大框架的一部分,并且标记为内联。我想知道BMI2指令集是否允许更短的版本?我正在使用的clang 4.0也会生成cmov版本。