胡闹了一下,发现是下面的
#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
?还是我遗漏了什么?
最佳答案
你编译时没有优化。在“调试”模式下构建时,GCC 不会努力选择特别合适的指令;它只专注于尽可能快地生成代码(并着眼于使调试更容易——例如,能够在源代码行上设置断点)。
当我通过传递 -O2
开关启用优化时,我得到:
_Z1fRi:
addl $1, (%rdi)
ret
对于通用调整,addl
是首选,因为 some Intel processors (specifically Pentium 4, but also possibly Knight's Landing) have a false flags dependency .
对于 -march=k8
,使用 incl
代替。
有时是 a use-case for leal
in optimized code ,不过,这就是当您想要递增寄存器的值并将结果存储在不同寄存器中时。以这种方式使用 leal
可以让您保留寄存器的原始值,而不需要额外的 movl
指令。 leal
相对于 incl
/addl
的另一个优点是 leal
不会影响标志,这很有用在指令调度中。
关于c++ - 为什么使用 leal 而不是 incq?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45171928/