我在鬼混,发现以下
#include <stdio.h>
void f(int& x){
x+=1;
}
int main(){
int a = 12;
f(a);
printf("%d\n",a);
}
由g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
翻译g++ main.cpp -S
时生成此程序集(仅显示相关部分)
_Z1fRi:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
leal 1(%rax), %edx
movq -8(%rbp), %rax
movl %edx, (%rax)
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl $12, -4(%rbp)
leaq -4(%rbp), %rax
movq %rax, %rdi
call _Z1fRi
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
ret
问题:为什么编译器会选择使用leal
而不是incq
?或者我错过了什么?
答案 0 :(得分:4)
您编译时没有优化。在“调试”模式下构建时,GCC不会努力选择特别合适的指令;它只关注尽可能快地生成代码(并着眼于使调试更容易 - 例如,,在源代码行上设置断点的能力)。
当我通过传递logstash.filters.mutate - Unknown setting 'syslog_pri' for mutate
开关启用优化时,我得到:
-O2
通过通用调整,_Z1fRi:
addl $1, (%rdi)
ret
是首选,因为some Intel processors (specifically Pentium 4, but also possibly Knight's Landing) have a false flags dependency。
使用addl
代替-march=k8
。
有时是a use-case for leal
in optimized code,这就是当你想增加寄存器的值并将结果存储在不同的寄存器中时。以这种方式使用incl
将允许您保留寄存器的原始值,而无需额外的leal
指令。 movl
优于leal
/ incl
的另一个优点是addl
不会影响标志,这在指令调度中非常有用。