Nasıl GCC kullanılmayan bir değişken bir döngü içinde artan optimize?
Bu basit bir C programı yazdım:
int main() {
int i;
int count = 0;
for(i = 0; i < 2000000000; i ){
count = count 1;
}
}
Gcc derleyici bu döngü (açık Ekle . optimize nasıl görmek istedim ^em>12000000000 kez "ekleyin2000000000bir kez"). Yani:
gcc test.cve sonra a.out
time
verir:
real 0m7.717s
user 0m7.710s
sys 0m0.000s
$ gcc -O2 test.cve sonra time on
.` verir:
real 0m0.003s
user 0m0.000s
sys 0m0.000s
Sonra gcc -S
ile de tamamladım. İlk oldukça açık görünüyor:
.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, L2 i < 2000000000
L3 1999999999
17 * ve döngüler karşılaştırın ekler.
Åžimdi optimize edilmiÅŸ
.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
Orada neler oluyor hiç anlamıyorum! Kurul çok az bilgi var, ama gibi bir şey bekliyordum
addl $2000000000, -8(%rbp)
Ben bile çalıştıgcc -c -g -Wa,-a,-ad-O2 test.cC kodu derleme ile beraber görmek için dönüştürülmüş, ama sonuç bir önceki ve daha açıktı.
Birisi kısaca açıklayabilir:
- -S -O2 gccçıktı.
- Eğer döngü (birçok meblağlar yerine bir miktar) beklediğim gibi optimize edilmiştir?
CEVAP
Derleyici o daha akıllı. :)
Aslında döngü sonucu kullanmadığınız bunu fark eder. Tüm döngü tamamen aldı!
Bu Dead Code Elimination denir.
Daha iyi bir test baskı sonucu
#include <stdio.h>
int main(void) {
int i; int count = 0;
for(i = 0; i < 2000000000; i ){
count = count 1;
}
// Print result to prevent Dead Code Elimination
printf("%d\n", count);
}
DÃœZENLEME :#include
olmadan bir sürümü karşılık gelir #include <stdio.h>
; MSVC montaj listesi gerekli ekledim ama aynı olmalıdır.
Windows içine çizme olduğum için şu an önümde GCC yok. Ama burada MSVC printf()
ile: sürüm demontaj
EDİT : yanlış montaj çıkış vardı. İşte doğru bir tane.
; 57 : int main(){
$LN8:
sub rsp, 40 ; 00000028H
; 58 :
; 59 :
; 60 : int i; int count = 0;
; 61 : for(i = 0; i < 2000000000; i ){
; 62 : count = count 1;
; 63 : }
; 64 :
; 65 : // Print result to prevent Dead Code Elimination
; 66 : printf("%d\n",count);
lea rcx, OFFSET FLAT:??_C@_03PMGGPEJJ@?$CFd?6?$AA@
mov edx, 2000000000 ; 77359400H
call QWORD PTR __imp_printf
; 67 :
; 68 :
; 69 :
; 70 :
; 71 : return 0;
xor eax, eax
; 72 : }
add rsp, 40 ; 00000028H
ret 0
Yani Evet, Visual Studio bu optimizasyon yapar. GCC muhtemelen de öyle kabul ediyorum.
Ve evet, GCC benzer bir optimizasyon gerçekleştirir. İşte gcc -S -O2 test.c
(gcc 4.5.2, Ubuntu 11.10, 86) ile aynı program için derleme bir listesi:
.file "test.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d\n"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
pushl ëp
movl %esp, ëp
andl $-16, %esp
subl $16, %esp
movl $2000000000, 8(%esp)
movl $.LC0, 4(%esp)
movl $1, (%esp)
call __printf_chk
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
Nasıl bir foreach döngü içinde ilk ve ...
Önce ya da döngü içinde değişken kavra...
Değişken için döngü içinde bildirilen ...
Bir döngü içinde bir değişken bildirme...
Bir döngü içinde nesne harfleri bir di...