c++ - 为什么使用 leal 而不是 incq?

标签 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.4g++ 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/

相关文章:

c++ - 指针变量可以保存另一个指针变量的地址吗?

c++ - Koenig Lookup 的奇怪行为

c++ - 如果我只有依赖程序的 .o 文件,我可以在可执行文件中反射(reflect)头文件的变化吗

c++ - QT 和 OpenCascade 内存不足

c++ - 编译器如何为类分配内存?

linux - 与 Linux 内核汇编中的引导加载程序

optimization - 如何优化我的 C/x86 代码?

assembly - 汇编程序 xbegin 引发非法指令

c++ - 无法解析符号 '__builtin_va_start' Visual Studio linux 远程调试

c++ - 在 main 中使用指向变量的指针的 Pthread 段错误