为什么使用leal而不是incq?

时间:2017-07-18 16:02:23

标签: c++ assembly g++ x86-64

我在鬼混,发现以下

#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?或者我错过了什么?

1 个答案:

答案 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不会影响标志,这在指令调度中非常有用。