如何优化我们默认的if-branch
How to optimize out default if-branch
我有以下代码位。给定如何调用foo,可以给GCC和Clang提供哪些编译器参数来像icc那样优化if语句?
代码:
#include <cstdlib>
int foo(int i, bool b = false)
{
if (b) ++i;
return ++i;
}
int boo(int i)
{
return ++i;
}
static const bool global_b = false;
int goo(int i, bool b = global_b)
{
if (b) ++i;
return ++i;
}
int main(int argc, char* argv[])
{
int i = atoi(argv[1]);
return 2 * foo(i) + 3 * boo(i) + 7 * goo(i);
}
GCC 4.9 -O2反汇编:
foo(int, bool):
cmp sil, 1
sbb edi, -1
lea eax, [rdi+1]
ret
goo(int, bool):
cmp sil, 1
sbb edi, -1
lea eax, [rdi+1]
ret
boo(int):
lea eax, [rdi+1]
ret
Clang 3.4 -O2拆卸:
foo(int, bool):
movzbl %sil, %eax
leal 1(%rdi,%rax), %eax
ret
goo(int, bool):
movzbl %sil, %eax
leal 1(%rdi,%rax), %eax
ret
boo(int):
leal 1(%rdi), %eax
ret
IntelCC 13 -O2拆卸:
foo(int, bool):
incl %edi
movl %edi, %eax
ret
goo(int):
incl %edi
movl %edi, %eax
ret
boo(int):
incl %edi
movl %edi, %eax
ret
模板化foo我们得到以下结果:
template <typename T>
T foo_t(T i, bool b = false)
{
if (b) ++i;
return ++i;
}
GCC 4.9隐式内联:
add eax, 1
英特尔编译器错误。如果没有像gcc的-fwhole-program
这样的选项(它会自动将除main
以外的所有函数标记为static
,即本地的这个翻译单元),我们不知道foo
是否从另一个翻译单元调用,所以编译器不能假设它总是被第二个参数等于false
调用。
有内联限定符,还有什么是增量的局部变量,已经通过值传递的点?这是一个优化版本:
#include <cstdlib>
inline int foo(int i, bool b = false)
{
// i is passed by value, no point incrementing it
//if (b) ++i;
//return ++i;
return (b)? i+2 : i+1;
}
inline int boo(int i)
{
// i is passed by value, no point incrementing it
return i+1;//++i;
}
static const bool global_b = false;
inline int goo(int i, bool b = global_b)
{
// i is passed by value, no point incrementing it
//if (b) ++i;
//return ++i;
return (b)? i+2 : i+1;
}
int main(int argc, char* argv[])
{
int i = atoi(argv[1]);
return 2 * foo(i) + 3 * boo(i) + 7 * goo(i);
}
尝试将foo
body改写为return i+1+b;
。
正如前面提到的,-fwhole-program
是成功的关键。
同样,你可以定义你的函数为静态的(内联也可以):
static int foo(int i, bool b = false)
{
if (b) ++i;
return ++i;
}
这将只生成:
add eax, 1
OP只讲述了故事的一部分:)。
gcc -O2
实际上内联了所有的函数调用,main
看起来像这样:
main:
subq $8, %rsp
movq 8(%rsi), %rdi
movl $10, %edx
xorl %esi, %esi
call strtol
addl $1, %eax
addq $8, %rsp
leal 0(,%rax,8), %edx
leal (%rdx,%rax,4), %eax
ret
相关文章:
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 如何使用默认参数等选择模板专业化
- 具有默认模板参数的多态类的模板推导失败
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 如果普通默认构造函数不执行任何操作,为什么我们不能使用 malloc 创建平凡可构造的对象?
- 为什么我们必须使用默认参数为模板类指定<>?
- 如果我们在c++中重载构造函数,那么默认构造函数是否仍然存在
- 在这种情况下,我们需要禁用默认的复制构造函数和赋值运算符
- 为什么我们只需要在头文件中声明默认参数
- 为什么我们可以检测 SFINAE 中 operator() 的默认参数值的存在,而不是自由函数和 PMF 的默认参数值
- 为什么我们不能从具有默认参数的函数调用函数?
- 我们如何确保传递的 2 个参数被视为第一个和第三个,而第二个 AD 第四个被视为默认值
- 为什么我们需要一个默认构造函数来通过引用传递对象C++
- 为什么我们不能重载构造函数来向其添加默认参数
- 如何优化我们默认的if-branch
- 我们可以依赖基于内存布局和默认析构函数的任何保证吗?
- 我们可以使用lambda表达式作为函数参数的默认值吗?
- 如果我们使用参数构造函数,我们是否需要在c++中提供默认构造函数
- 我们可以更改字符串流对象的重载运算符">>"默认行为吗?