Najczęstszymi miejscami krytycznymi programów są pętle
Optymalizacja pojedynczej instrukcji daje duży zysk dopiero
gdy ta instrukcja jest powtarzana wielokrotnie np. w pętli.
Narzut pętli to instrukcje potrzebne do skoku do początku pętli i do sprawdzenia warunku stopu.
Typowa pętla
for (int i = 0; i < n; i++) { // (loop body) }
Kod bez optymalizacji
mov ecx, [n] xor eax, eax ; i = 0 LoopTop: cmp eax, ecx ; i < n jge LoopEnd ; wyjście gdy i >= n ; (loop body) add eax, 1 ; i++ jmp LoopTop ; skok do początku LoopEnd:
Redukcja jednego skoku przez przesunięcie warunku na koniec
mov ecx, [n] test ecx, ecx jng LoopEnd ; opuść gdy n <= 0 xor eax, eax ; i = 0 LoopTop: ; (loop body) add eax, 1 ; i++ cmp eax, ecx ; i < n jl LoopTop ; kontynuuj jeżeli i < n LoopEnd:
Jeżeli nie potrzebujemy indeksu wewnątrz pętli możemy pozbyć się cmp odliczając w dół
mov ecx, [n] test ecx, ecx jng LoopEnd ; opuść gdy n <= 0 LoopTop: ; (loop body) sub ecx, 1 ; n-- jnz LoopTop ; kontynuuj jeżeli n!=0 LoopEnd:
Iterowanie od tyłu po tablicy jest nieoptymalne bo cache'owanie działa lepiej do przodu na a nie wstecz. Można to osiągnąć indeksując relatywnie do końca tablicy wartościami i = -n .. 1
mov ecx, [n] ; liczba elementów lea esi, [Array+4*ecx] ; wskaźnik na zaostatni element neg ecx ; i = -n jnl LoopEnd ; pomiń jeżeli (-n) >= 0 LoopTop: ; (Loop body) : dodajemy jeden do każdego elementu add dword [esi+4*ecx], 1 add ecx, 1 ; i++ js LoopTop ; powtorz jezeli i < 0 LoopEnd:
Strona 95.