【问题标题】:Why use leal instead of incq?为什么在 mcq 中使用铅而不是?
【发布时间】:2017-07-18 16:02:22
【问题描述】:

我胡闹,发现如下

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

【问题讨论】:

  • 请看优化后的代码。如果有差异,请更新您的帖子。
  • 在这种情况下如何使用incqincq 是一元的。并且编译器需要rdx = rax + 1。也许真正的问题是:为什么它选择涉及两个寄存器,其中一个就足够了(incq)?这是优化的代码吗?显然不是。
  • lea 也很有用,因为它不会影响任何标志寄存器值,这对于 x86[-64] 代码非常有用,其中有很多指令.这只是一个更好的范例。 inc 还引入了其他问题,例如部分标志寄存器停顿。真正的问题是为什么你会在这里使用inc而不是lea

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


【解决方案1】:

你编译时没有优化。在“调试”模式下构建时,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 不会影响标志,这在指令调度中很有用。

【讨论】:

  • 有趣的事实:-O0 代码是故意的,因为它想让你在任何断点处停止时用调试器修改内存中的变量,并且仍然有程序按书面执行。这就是为什么 everything 总是在语句(或源代码行?)之后溢出到内存,然后重新加载。遗憾的是,调试信息格式无法指定变量当前存在于寄存器中。
猜你喜欢
  • 2014-04-29
  • 2019-12-25
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
  • 2015-01-22
  • 2018-01-09
  • 2016-02-25
  • 1970-01-01
相关资源
最近更新 更多