web-dev-qa-db-ja.com

clangとgccの違い

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

コード処理と出力生成の点でどのように違いますか?たとえば、gccclangの両方に-O2最適化のオプション。コードを最適化するという点で、それらは同じ方法(高レベル)で動作していますか?たとえば、次のコードがある場合は、少しテストを行いました。

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

以下は、clangを使用した出力アセンブリと-O2を使用したgccです。

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

ご覧のとおり、出力には異なる命令が含まれています。だから私の質問は、それらのうちの1つが別のプロジェクトで別のものよりも有利ですか?

15
Pooya

はい。そしていや。

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

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

引数 here と多少関連性の低い here があります。

21
Honza Remeš

この場合、Clang出力は分岐しませんので、より良いです。代わりに、num % 2 == 1の値をalにロードします。gccによって生成されたコードはジャンプを使用します。 numが50%の確率で偶数/奇数であり、繰り返しパターンがないと予想される場合、GCCによって生成されるコードは 分岐予測エラーの影響を受けやすい になります。


ただし、GCCでもコードを適切に動作させることができます。

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

さらに、アルゴリズムは符号なしの数値のみに対して実際に定義されているように見えるため、unsigned int(負の数値では異なる)を使用する必要があります。実際には、unsigned int GCC/Clangが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

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

16
Antti Haapala