我怎样才能实现与英特尔指令的最小数量,没有一个分支或有条件的举动以下:坐落在无符号的所有位为1,如果相等,则为0
unsigned compare(unsigned x
,unsigned y) {
return (x == y)? ~0 : 0;
}
这是热码路径我需要最大限度地挤出。
我怎样才能实现与英特尔指令的最小数量,没有一个分支或有条件的举动以下:坐落在无符号的所有位为1,如果相等,则为0
unsigned compare(unsigned x
,unsigned y) {
return (x == y)? ~0 : 0;
}
这是热码路径我需要最大限度地挤出。
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关键字将其写入标题中。
这个函数确实是一个更大的框架的一部分(它标记为内联)。我想知道BMI2指令集是否允许更短的版本? –
铛4.0(这是我使用的)也产生一个cmov版本。 –
return -int(x==y)
是非常简洁的C++。编译器当然还是要把它变成高效的汇编。
因为int(true)==1
和unsigned (-1)==~0U
。
我想'x == y? 〜0:0'相当快。 '(x == y)*〜0'可能会更快。但是你应该在你的平台上试试这个(或者根据生成的汇编代码猜测)。 – Scheff
为什么'unsigned'而不是'bool'?我的意思是让它更有效率我会首先删除最明显的冗余,当一个单独一个就足以存储多个1s/0时 – user463035818
如果在“比特级”上优化是一个问题,值得一提[Bit Twiddling Hacks] (https://graphics.stanford.edu/~seander/bithacks.html)。 – Scheff