gccとclangでclangの方が顕著に最適化してくれてる例を見つけたのでメモがてら。
環境は
- GCC 4.9.2 20150212 (Red Hat 4.9.2-6)
- clang 3.5.0 (tags/RELEASE_350/final)
です。
テストコード
test.cpp
class S
{
private:
int a;
int b;
int c;
public:
S(const int aa, const int bb, const int cc)
: a(aa), b(bb), c(cc) {}
int A() const
{
return a;
}
int B() const
{
return b;
}
int C() const
{
return c;
}
};
template<typename F, typename G>
int Func(const S& s, const G& g, const F& f)
{
return f((s.*g)());
}
template<typename F, typename G>
int Func(const S& s, const G& g1, const G& g2, const F& f)
{
return f((s.*g1)(), (s.*g2)());
}
int P(const S& s)
{
return Func(s, &S::A, [](int a)
{
return a*5;
});
}
int p(const S& s)
{
return s.A()*5;
}
int Q(const S& s)
{
return Func(s, &S::A, &S::C, [](int a, int c)
{
return a+c;
});
}
int q(const S& s)
{
return s.A()+s.C();
}
を、まずclang++でコンパイルしてasmにします。
clang++ -std=c++11 test.cpp -S -O3
すると、
# P
imull $5, (%rdi), %eax
retq
# p
imull $5, (%rdi), %eax
retq
# Q
movl 8(%rdi), %eax
addl (%rdi), %eax
retq
# q
movl 8(%rdi), %eax
addl (%rdi), %eax
retq
うん、ちゃんとP=pでQ=qですね。最適化してくれてます。
一方、gccで
g++ -std=c++11 main.cpp -S -O3
とコンパイルすると
# P
subq $8, %rsp
call _ZNK1S1AEv
addq $8, %rsp
leal (%rax,%rax,4), %eax
ret
# p
movl (%rdi), %eax
leal (%rax,%rax,4), %eax
ret
# Q
pushq %rbp
pushq %rbx
movq %rdi, %rbx
subq $8, %rsp
call _ZNK1S1CEv
movq %rbx, %rdi
movl %eax, %ebp
call _ZNK1S1AEv
addq $8, %rsp
addl %ebp, %eax
popq %rbx
popq %rbp
ret
# q
movl 8(%rdi), %eax
addl (%rdi), %eax
ret
なんか律儀にcallしちゃってくれてますね・・・。
というわけでgccよりclangの方が良く最適化してくれてるという結果でした。
なお、*5の計算にclangはimulを使っている一方でgccはleaを使ってるという違いも面白いですね。某命令セット表を見てると、確かにimulよりはleaの方が速いっぽいので、その点ではgccの方が勝ってる気もします。