2017-07-18 3 views
-1

ich alberte herum und fand, dass die folgendeWarum leal anstelle von inq verwenden?

#include <stdio.h> 

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

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

, wenn sie von g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4 mit g++ main.cpp -S erzeugt diese Anordnung (zeigt nur die relevanten Teile) Frage

_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 

übersetzt: Warum sollte der Compiler wählen zu verwenden leal anstelle von incq? Oder fehlt mir etwas?

+2

Bitte schauen Sie sich den optimierten Code an. Und aktualisieren Sie Ihren Beitrag, wenn es Unterschiede gibt. –

+0

Wie würde es 'incq' in diesem Fall verwenden? 'incq' ist unär. Und der Compiler benötigt 'rdx = rax + 1'. Vielleicht ist die eigentliche Frage: Warum hat sie sich dafür entschieden, zwei Register einzubeziehen, in denen eines ausreichen würde (mit "incq")? Ist dieser optimierte Code? Scheinbar nicht. – AnT

+1

'lea' ist auch insofern nützlich, als es keine Flags-Registerwerte beeinflusst, was * sehr * nützlich für den x86 [-64] -Code ist, wo so viele Befehle dies tun. Es ist nur ein besseres Paradigma. 'inc' führte auch andere Probleme wie Partial Flags Register Stalls ein. Die wirkliche Frage ist * warum * würdest du 'inc' anstelle von' lea' hier verwenden? –

Antwort

4

Sie haben ohne Optimierung kompiliert. GCC unternimmt keine Anstrengungen, um besonders gut passende Anweisungen auszuwählen, wenn im "Debug" -Modus gebaut wird; es konzentriert sich nur darauf, den Code so schnell wie möglich zu erzeugen (und mit dem Ziel, das Debuggen zu erleichtern - , z. B., die Fähigkeit, Haltepunkte auf Quellcodezeilen zu setzen).

Wenn ich Optimierungen ermöglichen, den -O2 Schalter vorbei, die ich erhalten:

_Z1fRi: 
    addl $1, (%rdi) 
    ret 

Mit generic Tuning, die addl, weil some Intel processors (specifically Pentium 4, but also possibly Knight's Landing) have a false flags dependency bevorzugt.

Mit -march=k8 wird stattdessen incl verwendet.

Es ist manchmal a use-case for leal in optimized code, aber, und das ist, wenn Sie ein Register der Wert erhöhen möchten, und speichern Sie das Ergebnis in einem verschiedenen Register. Wenn Sie auf diese Weise leal verwenden, können Sie den ursprünglichen Wert des Registers beibehalten, ohne eine zusätzliche Anweisung movl zu benötigen. Ein weiterer Vorteil von leal über incl/addl ist, dass leal die Flags nicht beeinflusst, was bei der Befehlsplanung nützlich sein kann.

+0

Fun Tatsache: '-O0' Code ist absichtlich schrecklich, weil es Sie * Variablen * im Speicher mit einem Debugger ändern lassen wollen, während an jedem Haltepunkt gestoppt, und immer noch das Programm ausgeführt haben, wie geschrieben. Deshalb wird * alles * nach einer Anweisung (oder Quellzeile?) Immer in den Speicher ausgelagert und danach neu geladen. Debug-Info-Formate können leider nicht angeben, dass eine Variable momentan in einem Register aktiv ist. –

Verwandte Themen