2010-03-01 13 views
5

Gdy instrukcja continue jest używana w pętli kodu C, GCC tworzy nową etykietę z instrukcją nop tuż przed końcem bloku pętli i przeskakuje do niego, zamiast skakać do końca samego bloku pętli. Na przykład, następujące kod CGCC wygenerował zespół równoważny instrukcji continue w C

for (i=0; i<10; i++) { 
    puts("blah\n"); 
    if (i < 10) continue; 
    puts("This shouldn't be printed.\n"); 
} 

wytwarza następujący równoważnik ASM (gcc -S)

movl $0, 28(%esp) 
    jmp L2 
L5: 
    movl $LC0, (%esp) 
    call _puts 
    cmpl $9, 28(%esp) 
    jle L7 
L3: 
    movl $LC1, (%esp) 
    call _puts 
    jmp L4 
L7: 
    nop 
L4: 
    incl 28(%esp) 
L2: 
    cmpl $9, 28(%esp) 
    jle L5 

(if (I < 10) część jest włożony tak, że kompilator robi” t "zoptymalizuj" sekcję, usuwając wszystko, co następuje po instrukcji continue).

Moje pytanie brzmi: dlaczego nie przejść bezpośrednio do L4? IMO mogliśmy równie dobrze przejść do L4, czy coś mi brakuje?

Odpowiedz

4

To, co opisujesz, to optymalizacja. Z pewnością, jeśli powiesz gcc, aby zoptymalizować (wystarczy), zrobi dokładnie to, co opisujesz.

+0

Dzięki za szybką odpowiedź! -O1 zmyliło, chociaż przepływ programu po optymalizacji wydaje się teraz nieco mniej intuicyjny - chyba że się mylę, pętla wydaje się teraz częściowo rozwinięta. Ciekawi mnie teraz, czy istnieje zachęta do stworzenia etykiety za pomocą instrukcji nop. Czy jest jakaś sytuacja, w której to podejście zapobiegałoby temu, co by się stało, gdyby ktoś skoczył bezpośrednio na L4? – susmits

+0

Do celów debugowania można ustawić punkt przerwania w etykiecie L7 - trudno byłoby złamać dalej sprawę kontynuacji, jeśli jej tam nie było. – nos

+0

@susmits: Z -O1 zestaw jest mniej szczegółowy, ale pętla nie jest rozwijana (z -O3 możesz zobaczyć rozwiniętą wersję - zauważ, że nie zawiera nawet testu i <10 lub 2. puts()) . Generalnie tworzenie etykiety i niewykonywanie takich optymalizacji bardzo pomaga w debugowaniu. –

1

Domyślam się, że jest to symbol zastępczy dla jakiejś sekwencji poprawek z pominiętym kodem. Być może nazwa nop jest czasem zastępowana instrukcjami do przechowywania rejestrów na stosie lub niektórych takich.

Ale aby uzyskać więcej dowodów na to, pomoże znaleźć przykład, w którym nop jest zastąpiony przez coś innego.

+0

Myślę, że to jest prawdopodobnie to. W tym przypadku jest tak mało zmiennych, że zestaw zmiennych w rejestrach przy "kontynuacji" jest taki sam jak zbiór zmiennych w rejestrach po drugim zestawie. Jeśli tak nie było, to po L7 będzie kod do zsynchronizowania ich. Jeśli w pętli było wiele "kontynuacji", to każdy z nich musiał oczywiście zsynchronizować się z prawidłowym stanem L7 przed skokiem. –

+0

Z drugiej strony, umieszczenie takiego kodu w bloku powiązanym z instrukcją continue jest niezwykle nieefektywne, więc sądzę, że i tak jest to dość rzadki widok. –

+0

Pamiętaj, że susmits niejawnie zażądał nieefektywnego kodu (nie podając -O) ;-) –