web-dev-qa-db-fra.com

Différence entre clang et gcc

J'ai utilisé ces deux compilateurs dans différents projets.

Comment sont-ils différents en termes de traitement de code et de générations de sortie? Par exemple, gcc et clang contient -O2 options d'optimisation. Fonctionnent-ils de la même manière (haut niveau) en termes d'optimisation du code? J'ai fait un petit test, par exemple si j'ai le code suivant:

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

les assemblys de sortie avec clang et gcc avec -O2 sont les suivants:

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

comme on peut le voir, la sortie a des instructions différentes. Ma question est donc de savoir si l'un d'entre eux a un avantage sur un autre dans différents projets?

18
Pooya

Oui. Et non.

C'est comme demander si une voiture Audi a un avantage sur une voiture Mercedes. Comme eux, les deux compilateurs sont deux projets différents visant à faire la même chose. Dans certains cas, gcc émettra un meilleur code, dans d'autres, ce sera clang.

Lorsque vous avez besoin de savoir, vous devez compiler votre code avec les deux, puis le mesurer.

Il y a un argument ici et un peu moins lié ici .

22
Honza Remeš

Dans ce cas, la sortie Clang est meilleure, car elle ne se branche pas; à la place, il charge la valeur de num % 2 == 1 à al le code généré par gcc utilise des sauts. Si num devrait être pair/impair avec 50% de chances et sans répétition, le code généré par GCC sera susceptible d'échec de prédiction de branchement .


Cependant, vous pouvez également faire en sorte que le code se comporte bien sur GCC en faisant

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

Plus encore, comme il semble que votre algorithme soit vraiment défini uniquement pour les nombres non signés, vous devez utiliser unsigned int (ils sont différents pour les nombres négatifs) - en fait, vous obtenez une accélération majeure en utilisant unsigned int pour l'argument, comme maintenant GCC/Clang peut optimiser num % 2 à num & 1:

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

Le code résultant généré par gcc -O2

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

est bien meilleur que le code de votre fonction d'origine généré par l'un ou l'autre compilateur. Ainsi, un compilateur n'a pas autant d'importance qu'un programmeur qui sait ce qu'il fait.

16
Antti Haapala