clang和gcc之间的区别

Poo*_*oya 15 c optimization gcc clang

我在不同的项目中使用了这两个编译器.

它们在代码处理和输出生成方面有何不同?例如两者gccclang具有-O2优化的选项.它们在优化代码方面是否以相同的方式运行(高级别)?我做了一点测试,例如,如果我有以下代码:

int foo(int num) {
    if(num % 2 == 1)
        return num * num;
    else
        return num * num +1;  
}
Run Code Online (Sandbox Code Playgroud)

以下是带有-ng的clang和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
Run Code Online (Sandbox Code Playgroud)

可以看出输出有不同的指令.所以我的问题是其中一个在不同的项目中是否优于另一个?

Hon*_*meš 21

是.和不.

这就像询问奥迪汽车是否比梅赛德斯汽车更具优势.和他们一样,这两个编译器是两个不同的项目,旨在做同样的事情.在某些情况下,gcc会发出更好的代码,在其他情况下它会发出clang.

当您需要知道时,您必须用两者编译代码然后进行测量.

有一种说法在这里和稍差相关这里.


Ant*_*ala 16

在这种情况下,Clang输出更好,因为它不分支; 相反,它将值加载num % 2 == 1al由gcc使用跳转生成的代码中.如果num预期是偶数/奇数,具有50%的几率,并且没有重复模式,则GCC生成的代码将易受分支预测失败的影响.


但是,你可以通过这样做在GCC上使代码表现良好

int foo(int num) {
    return num * num + (num % 2 != 1);
}
Run Code Online (Sandbox Code Playgroud)

更重要的是,因为你的算法似乎只是为无符号数定义,你应该使用unsigned int(它们对于负数是不同的) - 实际上你通过使用unsigned int参数来获得一个主要的加速,因为现在GCC/Clang可以优化num % 2num & 1:

unsigned int foo(unsigned int num) {
    return num * num + (num % 2 != 1);
}
Run Code Online (Sandbox Code Playgroud)

生成的代码由 gcc -O2

movl    %edi, %edx
imull   %edi, %edi
andl    $1, %edx
xorl    $1, %edx
leal    (%rdi,%rdx), %eax
ret
Run Code Online (Sandbox Code Playgroud)

比任何一个编译器生成的原始函数的代码要好得多.因此,编译器与知道他正在做什么的程序员一样重要.