2017-07-18 126 views
-1

我打打鬧鬧,發現以下爲什麼使用leal而不是incq?

#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?或者我錯過了什麼?

+2

請看優化代碼。如果有差異,請更新您的帖子。 –

+0

在這種情況下,它如何使用'incq'? 'incq'是一元的。編譯器需要'rdx = rax + 1'。也許真正的問題是:爲什麼它選擇包含兩個寄存器,其中一個就足夠了(使用'incq')?這是優化的代碼?顯然不是。 – AnT

+1

'lea'也是有用的,因爲它不會影響任何標誌寄存器值,這對於x86 [-64]代碼非常有用,在那裏有很多指令。這只是一個更好的範例。 inc還介紹了其他問題,例如部分標誌寄存器攤位。真正的問題是*爲什麼*你會在這裏使用'inc'而不是'lea'? –

回答

4

您編譯沒有優化。在建立「調試」模式時,GCC不會做出任何努力來選擇特別合適的指令;它只是集中在儘可能快地生成代碼(和着眼於使調試easier- 例如,設置在源代碼行斷點的能力)。

當我能夠通過將-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=k8incl來代替。

有時a use-case for leal in optimized code,雖然,那就是當你想增加一個寄存器的值,並將結果在不同寄存器。通過這種方式使用leal將允許您保存寄存器的原始值,而不需要額外的指令movl。的leal超過incl/addl另一個優點是,leal不影響標誌,其可以是在指令調度是有用的。

+0

有趣的事實:'-O0'代碼是可怕的目的,因爲它想要讓你*修改*變量與調試器,而記憶停在任何斷點,仍然有程序執行書面。這就是爲什麼*在語句(或源代碼行?)之後,* everything *總是會溢出到內存中,並在之後重新加載。不幸的是,調試信息格式無法指定變量當前是否在寄存器中。 –

相關問題