2012-03-20 14 views
5

Słyszałem, jak ktoś powiedział, że kompilatory często przesuwają warunki pętli na dół pętli. Oznacza to, że pętle, takie jak:Dlaczego preferowana jest dolna pętla testowa?

while (condition) { 
    ... 
} 

zostaje zmieniony na:

if (condition) { 
    do { 
     ... 
    } while (condition); 
} 

dotyczące maszyny niezależną optymalizację, dlaczego korzystne jest ostatni?

+0

W rzeczywistości druga pętla nie ocenia stanu u góry pętli. Przeskakuje do warunku while, gdzie trwa tak, jakby właśnie zakończył iterację. –

Odpowiedz

7

Bez optymalizacji kompilatora, pierwsza pętla przechodzi do kodu montażowej tak:

@@: 
cmp ... ; or test ... 
jz @f 

... 
jmp @b 

Podczas gdy druga pętla idzie mniej więcej tak:

jmp bottom 

    @@: 
... 

    bottom: 
cmp ... ; or test ... 
jz @b 

Warunkowe skoki są zwykle przewidywanej jakie należy podjąć więc pierwsza metoda może potencjalnie prowadzić do większej liczby opróżnień bufora potoku/instrukcji.

Jednak najważniejsze jest to, że dla pierwszej pętli dostępne są dwie gałęzie na iterację pętli (2N), podczas gdy w drugiej, każda iteracja pętli ma tylko jedną gałąź ze stałym obciążeniem pierwszego bezwarunkowego skoku (N+1).

Aby uzyskać więcej informacji na temat optymalizacji pętli, patrz strona 88 tego assembly optimisation guide.

+2

+1 za wymienienie predyktora gałęzi, jednak zapomniałeś o bezwarunkowym skoku w drugim przykładzie. (Drugi przykład to pętla 'do', chcemy pętlę' while'.) Nie masz racji mówiąc, że druga pętla zajmuje mniej miejsca. –

+0

@KendallFrey: Dobry połów, zaktualizowałem kod. –

+0

Czy CFG zbudowana z drugiej "struktury pętli" ma jakąkolwiek zaletę, która nie występuje podczas konstruowania jej z pierwszej pętli? Mam na myśli, czy jest to bardziej podatne na optymalizację? – JohnTortugo

0

Po części się mylisz. Typowa optymalizacja jest taka:

jmp $test; 
$loop: 
    ; loop statements 
$test: 
    test <condition>; 
    branch-true $loop; 

zamiast tego:

$loop: 
    test <condition>; 
    branch-false $end; 
    ; loop statements 
    branch loop; 
$end: 

który posiada dwa oddziały w każdej iteracji pętli. Kolejną zaletą jest to, że część po początkowym skoku jest identyczna z kodem wygenerowanym dla do/while.

0

W widoku złożenia pętla jest po prostu instrukcją skoku, która przeskakuje do tyłu kodu. Tak więc kompilator musi wstawić skok na końcu pętli.

Wiele zestawów instrukcji, takich jak x86, ARM, MIPS, zawiera instrukcje warunkowego skoku/rozgałęzienia. Czy skok odbędzie się w zależności od warunku określonego w instrukcji.

Tak więc kompilatory preferują tego rodzaju instrukcje i przenoszą warunek na koniec pętli, aby skorzystać z instrukcji.

Powiązane problemy