如何优化我们默认的if-branch

How to optimize out default if-branch

本文关键字:我们 默认 if-branch 优化 何优化      更新时间:2023-10-16

我有以下代码位。给定如何调用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
相关文章: