37 votes

Pourquoi GCC déplace-t-il les variables vers un emplacement temporaire avant de les assigner ?

En regardant un code C décompilé, j'ai vu ceci :

movl    -0xc(%rbp), %esi
movl    %esi, -0x8(%rbp)

Cela correspond à ce code C :

x = y;

Cela m'a fait réfléchir : comment se fait-il que gcc déplace y à %esi et ensuite déplacer %esi à x au lieu de simplement bouger y à x directement ?


Voici l'intégralité du code C et décompilé, si cela a de l'importance :

C

int main(void) {
    int x, y, z;

    while(1) {
        x = 0;
        y = 1;
        do {
            printf("%d\n", x);

            z = x + y;
            x = y;
            y = z;
        } while(x < 255);
    }
}

Décompilé

pushq    %rbp
movq     %rsp, %rbp
subq     $0x20, %rsp
movl     $0x0, -0x4(%rbp)

movl     $0x0, -0x8(%rbp) ; x = 0
movl     $0x1, -0xc(%rbp) ; y = 1

; printf
leaq     0x56(%rip), %rdi
movl     -0x8(%rbp), %esi
movb     $0x0, %al
callq    0x100000f78

; z = x + y
movl     -0x8(%rbp), %esi  ; x -> esi
addl     -0xc(%rbp), %esi  ; y + esi
movl     %esi, -0x10(%rbp) ; z = esi

; x = y
movl     -0xc(%rbp), %esi
movl     %esi, -0x8(%rbp)

; y = z
movl     -0x10(%rbp), %esi
movl     %esi, -0xc(%rbp)

movl     %eax, -0x14(%rbp) ; not sure... I believe printf return value?
cmpl     $0xff, -0x8(%rbp) ; x < 255
jl       0x100000f3d ; do...while(x < 255)
jmp      0x100000f2f ; while(1)

0 votes

Un transfert direct de mémoire à mémoire (s'il est possible dans le monde x86, je ne m'en souviens pas) nécessiterait toujours que le cœur du processeur stocke la valeur en interne d'une manière ou d'une autre dans le cadre de la lecture de la mémoire.

3 votes

Probablement parce que vous ne demandez pas au compilateur d'appliquer tout optimisations : godbolt.org/g/SKUrDo

5 votes

De plus, le code est-il construit avec ou sans optimisations ?

75voto

interjay Points 51000

La plupart des instructions x86 (autres que certaines instructions spécialisées telles que movsb ) ne peut accéder qu'à un seul emplacement mémoire. Par conséquent, pour passer d'une mémoire à l'autre, il faut passer par un registre à deux emplacements de mémoire. mov des instructions.

Le site mov peut être utilisée de la manière suivante :

mov mem, reg
mov reg, mem
mov reg, reg
mov reg, imm
mov mem, imm

Il n'y a pas mov mem, mem .

Notez que si vous aviez compilé avec des optimisations, les variables seraient placées dans des registres et cela ne serait pas un problème.

3 votes

Il convient également de noter que les instructions, qui peut accèdent à deux emplacements de mémoire et doivent être précédées de plusieurs instructions pour préparer les registres (comme les instructions DS:ESI / RSI et ES:EDI / RDI pour movs ). Cela supprimerait en tout cas tout avantage potentiel de l'utilisation de ces instructions pour copier un seul mot-clé de mémoire à mémoire, même s'il y en aurait un autrement.

0 votes

Quoi qu'il en soit, l'unité centrale ne peut pas simultanément lire à partir d'un emplacement de mémoire et écrire immédiatement les mêmes données dans un autre emplacement, elle doit donc enregistrer la valeur dans une mémoire interne entre la lecture et l'écriture. Avec toutes les optimisations en cours dans les CPU modernes, je suppose qu'il n'y aurait aucune différence d'exécution entre la séquence de 2 codes et l'hypothétique "mov mem,mem".

0 votes

movs? Les instructions ne sont pas les seules. PUSH et POP avec un opérande mémoire ont un emplacement mémoire explicite (l'opérande) et un emplacement mémoire implicite (la pile)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X