2017-07-06 17 views
1

我怎样才能实现与英特尔指令的最小数量,没有一个分支或有条件的举动以下:坐落在无符号的所有位为1,如果相等,则为0

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

这是热码路径我需要最大限度地挤出。

+2

我想'x == y? 〜0:0'相当快。 '(x == y)*〜0'可能会更快。但是你应该在你的平台上试试这个(或者根据生成的汇编代码猜测)。 – Scheff

+0

为什么'unsigned'而不是'bool'?我的意思是让它更有效率我会首先删除最明显的冗余,当一个单独一个就足以存储多个1s/0时 – user463035818

+0

如果在“比特级”上优化是一个问题,值得一提[Bit Twiddling Hacks] (https://graphics.stanford.edu/~seander/bithacks.html)。 – Scheff

回答

4

GCC解决了这个很好的,并与-02和高达编译时就知道了否定招:

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 

,Visual Studio生成以下代码:

compare2, COMDAT PROC 
     xor  eax, eax 
     or  r8d, -1     ; ffffffffH 
     cmp  ecx, edx 
     cmove eax, r8d 
     ret  0 
compare2 ENDP 
compare, COMDAT PROC 
     xor  eax, eax 
     cmp  ecx, edx 
     setne al 
     dec  eax 
     ret  0 
compare ENDP 

这似乎是第一个版本避免了有条件的移动(请注意函数的顺序已更改)。

要查看其他编译器的解决方案,尝试将代码粘贴到 https://gcc.godbolt.org/(添加优化标志)。

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

另外我不会那么肯定一个条件寄存器移动比其他操作慢。

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

因此,假设您的代码中的确是一个函数,请使用inline关键字将其写入标题中。

+0

这个函数确实是一个更大的框架的一部分(它标记为内联)。我想知道BMI2指令集是否允许更短的版本? –

+0

铛4.0(这是我使用的)也产生一个cmov版本。 –

3

return -int(x==y)是非常简洁的C++。编译器当然还是要把它变成高效的汇编。

因为int(true)==1unsigned (-1)==~0U

相关问题