我有以下一点代码。鉴于如何调用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
Templatising foo 我们得到以下内容:
template <typename T>
T foo_t(T i, bool b = false)
{
if (b) ++i;
return ++i;
}
GCC 4.9隐式内联:
add eax, 1
答案 0 :(得分:4)
英特尔的编译器错了。如果没有像gcc -fwhole-program
这样的选项(它会自动将所有功能标记为main
而不是static
,即此翻译单元的本地功能),我们就不知道{是{从另一个翻译单元调用{1}},因此编译器不能假定它总是使用等于foo
的第二个参数调用。
答案 1 :(得分:1)
是否具有内联限定符,以及递增已通过值传递的局部变量的重点是什么?这是一个优化版本:
#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);
}
答案 2 :(得分:0)
尝试将foo
正文重写为return i+1+b;
。
答案 3 :(得分:0)
如前所述,-fwhole-program
是成功的关键。
此外,您可以将函数定义为静态(内联也可以):
static int foo(int i, bool b = false)
{
if (b) ++i;
return ++i;
}
这将只生成:
add eax, 1
答案 4 :(得分:0)
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