【发布时间】:2017-03-30 12:12:29
【问题描述】:
我有一个函数可以找到给定整数的二的下一个幂。如果整数是 2 的幂,则返回幂。
非常简单:
char nextpow2if(int a)
{
char foo = char(32 - __builtin_clz(a));
bool ispow2 = !(a & a-1);
if (ispow2) --foo;
return foo;
}
但是,在使用 gcc 6 和 -O2 编译后,在检查生成的程序集后,我发现这是在计算 foo-1 后使用看似无用的指令 cmovne 编译的。更糟糕的是,使用 gcc5 和更早版本时,我在代码中得到了一个实际的 jne 分支。
编译它的更快方法就像我编写了以下函数:
char nextpow2sub(int a)
{
char foo = char(32 - __builtin_clz(a));
bool ispow2 = !(a & a-1);
return foo - ispow2;
}
此代码已被所有编译器正确编译为最短(和最快)可能的程序集,带有 sete 和布尔减法。
为什么编译器无法优化第一个?这似乎是一个非常容易识别的案例。为什么 gcc 5 和更早版本将其编译为实际的 jne 分支?两个版本之间是否存在我看不到的边缘情况,这可能导致它们的行为不同?
PS:现场演示here
编辑:我还没有测试过 gcc 6 的性能,但 gcc 5 的性能大约快了两倍(至少在合成性能测试中)。这就是我真正提出这个问题的原因。
【问题讨论】:
-
不要为不相关的语言发送垃圾标签!
-
“编译这个更快的方法就像我编写了以下函数一样:” 你测量了吗?速度快多少?
-
您是按生成的汇编代码数量来比较性能吗?这不是一个好方法(尽管在某些情况下可能是这样)。
-
在 GCC 5 上,后者大约快两倍。
-
这不是一个抱怨,而是一个问题(这可能会变成向适当的人抱怨:))也许代码中有一些东西使它无法优化。我看不到,但也许有人可以。或者具有适当知识的人可能会说这是一个实际已知的编译器问题
标签: c++ g++ compiler-optimization