2017-07-18 4 views
-1

私は質問浮気とg++ main.cpp -Sg++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4によって翻訳された以下のなぜincqの代わりにlealを使用するのですか?

#include <stdio.h> 

void f(int& x){ 
    x+=1; 
} 

int main(){ 
    int a = 12; 
    f(a); 
    printf("%d\n",a); 
} 

が(関連部分のみを示す)は、このアセンブリを生産することを見出した

_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 

た:なぜコンパイラが選ぶだろうincqの代わりにlealを使用しますか?または私は何かを逃していますか?

+2

最適化されたコードをご覧ください。違いがある場合は、あなたの投稿を更新してください。 –

+0

この場合、 'incq'はどのように使用されますか? 'incq'は単項式です。コンパイラには 'rdx = rax + 1'が必要です。おそらく本当の問題は、(incqで)十分なところに2つのレジスタを含めることを選択した理由は?この最適化されたコードですか?どうやらない。 – AnT

+1

'lea'はフラグレジスタの値に影響を与えない点でも便利です。これは非常に多くの指示があるx86 [-64]コードにとっては非常に便利です。それはもっと良いパラダイムです。 'inc'は、部分フラグレジスタの停止のような他の問題も導入しました。本当の疑問は、なぜここで 'lea'の代わりに' inc'を使うのですか? –

答えて

4

最適化せずにコンパイルしました。 GCCは、「デバッグ」モードでビルドするときに、特に適切な指示を選択するような努力はしていません。できるだけ早くコードを生成することに集中しています(そして、デバッグを容易にするために、例えば、ソースコード行にブレークポイントを設定する機能)。

私は-O2スイッチを渡すことによって、最適化を有効にすると、私が手:

_Z1fRi: 
    addl $1, (%rdi) 
    ret 

一般的なチューニングでは、addlsome 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であることは、フラグに影響しないことであり、これは命令スケジューリングに役立つことがあります。

+0

面白い事実: '-O0'コードは、ブレークポイントで停止している間にデバッガでメモリ内の変数を変更し、プログラムを実行済みにしておきたいので、無駄です。これは、*すべての*が常にステートメント(またはソース行?)の後にメモリに流され、後で再ロードされる理由です。デバッグ情報形式では、残念ながら変数が現在レジスタに存在することを指定することはできません。 –

関連する問題