2013-03-30 13 views
5

Ho il seguente semplice programma che sto usando per rinfrescare la memoria di GDB (che non ho toccato per molti anni).GCC cambia meno di o uguale a

#include <stdio.h> 

int main() 
{ 
    int i; 

    for (i = 0; i < 10; i++) 
    { 
    printf("Hello World\n"); 
    } 

    return 0; 
} 

Compilare questo con gcc -g for-test.c -o for-test. In base alla pagina man, non mi aspetto alcuna ottimizzazione da utilizzare, poiché non ne ho specificato nessuna.

Quando carico questo in GDB e corro disassemble main, il confronto i < 10 genera il seguente:

cmp DWORD PTR [rbp-0x4],0x9 
jle 0x4004fe <main+10> 

Questo sembra avere cambiato in modo efficace un confronto di i < 10-i <= 9. Dato che si tratta di confronti interi, non dovrebbe esserci una differenza, ma mi chiedevo se c'è qualche motivo per cui GCC emette questo assembly, invece di confrontarlo con 10 e saltando se inferiore a (JL)?

Modifica: questo è su una macchina con un processore a 64 bit, che esegue Ubuntu con GCC 4.6.3 e GDB 7.4-2012.04.

+0

Entrambi i modi sono identici al 100% (stesso comportamento, stessa dimensione del codice, stessa velocità su ogni CPU). Non conosco gli interni di GCC, quindi non riesco a indovinare perché lo abbia fatto. Più interessante è che non penso che tu abbia abilitato l'ottimizzazione (altrimenti userebbe un registro invece di una variabile locale per 'i'). – Brendan

+2

Forse è così che normalizza i confronti .. – harold

+0

Se ci fosse qualche possibilità che i due non fossero gli stessi, non lo farebbe senza l'ottimizzazione. per esempio. 'if (a + 1> 1)' sarà semplificato a 'if (a> 0)' con l'ottimizzazione, ma è potenzialmente pericoloso, quindi non sarà fatto altrimenti. – teppic

risposta

5

Non ci deve essere alcuna differenza nella velocità di esecuzione. Penso che gcc generalmente emetta jle per tali confronti e lo fa per coerenza nell'assemblaggio generato.

+0

Questo sembra essere il caso. È interessante notare che ho provato lo stesso codice in clang e il risultato era l'opposto: convertiva un "ciclo continuo se inferiore a" in "ciclo di interruzione se maggiore o uguale a". Non sono sicuro del motivo per cui i due compilatori hanno scelto percorsi diversi o se uno è intrinsecamente più efficiente dell'altro. – pwaring

0

Non è l'ottimizzazione efficace, solo un altro modo di scrivere lo stesso. La compilazione con flag -O genera ottimizzazioni molto più complesse.

2

I compilatori possono eseguire ottimizzazioni purché il comportamento osservabile sia lo stesso. Questo è noto come As-If rule. Poiché il comportamento osservabile per entrambi i casi è lo stesso, il compilatore può generare il codice assembly in uno dei due. Questo è vero anche se non hai abilitato nessuna ottimizzazione.

+0

+1. Potrebbe anche srotolare il ciclo (lo fa effettivamente con '-O3'). E, forse, anche stampare una singola stringa che è di 10 copie dell'originale. –

+0

Tuttavia, non è proprio un'ottimizzazione, a meno che il confronto con 9 e il salto se minore o uguale sia più veloce (o più efficiente in termini di memoria o qualche altra misura) rispetto al confronto con 10 e salto se inferiore a. – pwaring

Problemi correlati