Poo*_*oya 15 c optimization gcc clang
我在不同的项目中使用了这两个编译器.
它们在代码处理和输出生成方面有何不同?例如两者gcc
并clang
具有-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)
可以看出输出有不同的指令.所以我的问题是其中一个在不同的项目中是否优于另一个?
Ant*_*ala 16
在这种情况下,Clang输出更好,因为它不分支; 相反,它将值加载num % 2 == 1
到al
由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 % 2
到num & 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)
比任何一个编译器生成的原始函数的代码要好得多.因此,编译器与知道他正在做什么的程序员一样重要.