3

我有以下代码。鉴于 foo 是如何被调用的,GCC 和 Clang 可以提供哪些编译器参数来优化 if 语句,就像 icc 一样?

代码:

#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
4

5 回答 5

4

英特尔的编译器是错误的。如果没有像 gcc's 之类的选项-fwhole-program(它会自动将所有函数标记mainstatic,即此翻译单元的本地函数),我们不知道是否foo从另一个翻译单元调用,因此编译器不能假设它总是用第二个参数调用 equal到false.

于 2014-08-21T06:40:41.157 回答
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);
}
于 2014-08-27T09:43:34.217 回答
0

尝试将foobody 重写为return i+1+b;.

于 2014-08-21T06:44:24.770 回答
0

如前所述,是-fwhole-program成功的关键。

此外,您可以将函数定义为静态(内联也可以):

static int foo(int i, bool b = false)
{
   if (b) ++i;
   return ++i;
}

这只会生成:

add eax, 1
于 2014-08-21T06:55:08.163 回答
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
于 2014-08-21T06:57:16.643 回答