2016-04-11 20 views
8

私はこれらの両方のコンパイラを異なるプロジェクトで使用しました。clangとgccの違い

コード処理と出力世代の違いはどうですか?例えば、gccclangの両方には、最適化のために-O2オプションがあります。彼らはコードを最適化するという点で同じレベル(高レベル)で動作していますか?それは出力を見ることができるように

----gcc 5.3.0-----        ----clang 3.8.0---- 
foo(int):          foo(int): 
     movl %edi, %edx        movl %edi, %eax 
     shrl $31, %edx        shrl $31, %eax 
     leal (%rdi,%rdx), %eax      addl %edi, %eax 
     andl $1, %eax        andl $-2, %eax 
     subl %edx, %eax        movl %edi, %ecx 
     cmpl $1, %eax        subl %eax, %ecx 
     je  .L5          imull %edi, %edi 
     imull %edi, %edi        cmpl $1, %ecx 
     leal 1(%rdi), %eax       setne %al 
     ret            movzbl %al, %eax 
.L5:             addl %edi, %eax 
     movl %edi, %eax        retq 
     imull %edi, %eax 
     ret 

:以下

int foo(int num) { 
    if(num % 2 == 1) 
     return num * num; 
    else 
     return num * num +1; 
} 

は-O2と打ち鳴らすとgccで出力アセンブリです:私は、私は次のコードを持っている場合など、少しテストをしました異なる指示がある。だから私の質問は、彼らの1つは、別のプロジェクトで別のものよりも優位性がありますか?

+2

代わりに 'int foo(int num){return num * num +〜num & 1;}'と書いてコードを改善することができます。 – fuz

+1

@FUZxxl:すごくいい点は、もっと良いコードを作ることです(https://godbolt.org/g/Y1RZuj)が、int foo(int num){return num * num +(〜num & 1);} '〜'は*や+よりも優先順位が低いため、負の数では異なる動作をしますので、Cでは '-1%2 'は' -1'なので、ifはfalseです。 'n * n +(n%2)'と書いてください。 –

+0

@FUZxxl注釈のおかげで、どのコンパイラが何を出力するかを調べるだけの簡単なテストになります。 – Pooya

答えて

12

はい。そして、いいえ。

これは、アウディ車がメルセデス車よりも有利かどうかを尋ねるようなものです。同じように、2つのコンパイラは同じことを目指す2つの異なるプロジェクトです。場合によってはgccがより良いコードを出力し、他の場合はclangになります。

知っておく必要がある場合は、両方でコードをコンパイルしてから測定する必要があります。

hereという引数があり、やや関連性が低いhereです。

10

この場合、分岐しないのでClang出力が優れています。代わりにnum % 2 == 1の値をalにロードします.gccによって生成されたコードはジャンプを使用します。 numが50%の確率で偶数/奇数であると予想され、繰り返しパターンがない場合、GCCによって生成されるコードはsusceptible to branch prediction failureになります。あなたはそれがあなたのアルゴリズムは本当に唯一の符号なしの数字のために定義されているようだとして、あなたが使用する必要があり、さらにその

int foo(int num) { 
    return num * num + (num % 2 != 1); 
} 

を行うことによって、同様GCCでコードが行儀作ることができますしかし


unsigned int(彼らは負の数に異なるなら) - 今GCC /クランを最適化できるよう実際には、引数にunsigned intを使用することにより、主要な高速化を得るnum % 2num & 1へ:

unsigned int foo(unsigned int num) { 
    return num * num + (num % 2 != 1); 
} 

gcc -O2

movl %edi, %edx 
imull %edi, %edi 
andl $1, %edx 
xorl $1, %edx 
leal (%rdi,%rdx), %eax 
ret 

によって生成されたコードは、どちらかのコンパイラによって生成された元の関数のコードよりもはるかに優れています。したがって、コンパイラは、自分が何をしているかを知っているプログラマーほど重要ではありません。

+1

私は間違いを犯したでしょう。もちろん、!= 1、または== 0であったはずです。 –

関連する問題