这是我试图实现的目标。这很简单:
unsigned int foo1(bool cond, unsigned int num)
{
return cond ? num : 0;
}
Assmebly:
test dil, dil
mov eax, 0
cmovne eax, esi
ret
我的问题是,有更快的方法吗?以下是我想到的一些方法:
unsigned int foo2(bool cond, unsigned int num)
{
return cond * num;
}
ASSMBLY:
movzx eax, dil
imul eax, esi
ret
unsigned int foo3(bool cond, unsigned int num)
{
static const unsigned int masks[2] = { 0x0, 0xFFFFFFFF };
return masks[cond] & num;
}
大会:
movzx edi, dil
mov eax, DWORD PTR foo3(bool, unsigned int)::masks[0+rdi*4]
and eax, esi
ret
unsigned int foo4(bool cond, unsigned int num)
{
return (0 - (unsigned)cond) & num;
}
大会:
movzx eax, dil
neg eax
and eax, esi
ret
现在,乘法产生最少的指令,我认为它是最好的选择,但我不确定imul。有什么建议吗?
提前致谢,
答案 0 :(得分:1)
乘法和内存访问比简单的if语句花费更多时间。如果您想优化此代码,最好的方法是仅使用"和"或"或"指令(将其设置为内联以避免函数调用)。
这是一个优化的'使用蒙版而不是布尔值的函数示例:
inline unsigned int foo1(unsigned int mask, unsigned int num)
{
return mask & num;
}
您的电话将如下所示:
foo1(0, 10); /* Returns 0 */
foo1(~0, 10); /* Returns 10 */
答案 1 :(得分:1)
优化代码并不总是像计算汇编程序指令和CPU标记一样简单。
乘法方法在大多数系统上可能是最快的,因为它删除了一个分支。在大多数CPU内核上,乘法指令应该相当快。
你可以考虑的是,如果你真的需要使用这么大的整数类型。在小型8位或16位CPU上,以下代码会明显加快:
uint_fast16_t foo2(bool cond, uint_fast16_t num)
{
return (uint_fast16_t)cond * num;
}
另一方面,这些CPU很少带有分支预测或指令缓存。
您不必担心手动功能内联。编译器将在大多数编译器上自动内联此函数。
答案 2 :(得分:0)
观看所有精彩的答案和评论,
我认为这是正确答案:
当达到微观优化水平时,没有“最佳”选择,因为它可能因平台,操作系统和书面软件而异。
因此,在我看来,软件方面的正确方法是创建多个实现,并使用一些抽象封装它们,以便可以轻松切换。
在进行基准测试时,在它们之间切换以查看哪一个产生了最佳的情况。
当然,我们可以排除明显比其他解决方案更差的解决方案。