J'ai écrit ce simple programme en C :
int main() {
int i;
int count = 0;
for(i = 0; i < 2000000000; i++){
count = count + 1;
}
}
Je voulais voir comment le compilateur gcc optimise cette boucle (ajouter clairement 1 2000000000 fois devrait être "ajouter 2000000000 une fois"). Donc :
gcc test.c et ensuite time
sur a.out
donne :
real 0m7.717s
user 0m7.710s
sys 0m0.000s
$ gcc -O2 test.c et ensuite time on
a.out` donne :
real 0m0.003s
user 0m0.000s
sys 0m0.000s
Puis j'ai démonté les deux avec gcc -S
. La première semble assez claire :
.file "test.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, -8(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L3:
addl $1, -8(%rbp)
addl $1, -4(%rbp)
.L2:
cmpl $1999999999, -4(%rbp)
jle .L3
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
L3 ajoute, L2 compare -4(%rbp)
avec 1999999999
et boucle vers L3 si i < 2000000000
.
Maintenant, l'optimisé :
.file "test.c"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
rep
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
Je ne comprends pas du tout ce qui se passe là-bas ! J'ai peu de connaissances en assemblage, mais je m'attendais à quelque chose comme
addl $2000000000, -8(%rbp)
J'ai même essayé avec gcc -c -g -Wa,-a,-ad -O2 test.c pour voir le code C ainsi que l'assemblage vers lequel il a été converti, mais le résultat n'était pas plus clair que le précédent.
Quelqu'un peut-il m'expliquer brièvement :
- Le site gcc -S -O2 sortie.
- Si la boucle est optimisée comme je le pensais (une seule somme au lieu de plusieurs) ?