У меня есть следующий фрагмент кода. Учитывая, как вызывается 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
Templatising Foo мы получаем следующее:
template <typename T>
T foo_t(T i, bool b = false)
{
if (b) ++i;
return ++i;
}
GCC 4.9 неявно встроен:
add eax, 1
Компилятор Intel не так. Без опции как у 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
тело как return i+1+b;
,
Как было упомянуто -fwhole-program
это ключ к успеху.
Кроме того, вы можете определить вашу функцию как статическую (inline тоже будет работать):
static int foo(int i, bool b = false)
{
if (b) ++i;
return ++i;
}
это будет генерировать только:
add eax, 1
ОП рассказывает только часть истории :).
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