2015-06-10 23 views
10

Si consideri il seguente, semplice programma (adattato da this question):Perché questo programma non è ottimizzato?

#include <cstdlib> 

int main(int argc, char** argv) { 
    int mul1[10] = { 4, 1, 8, 6, 3, 2, 5, 8, 6, 7 }; // sum = 50 
    int mul2[10] = { 4, 1, 8, 6, 7, 9, 5, 1, 2, 3 }; // sum = 46 

    int x1 = std::atoi(argv[1]); 
    int x2 = std::atoi(argv[2]); 

    int result = 0; 

    // For each element in mul1/mul2, accumulate the product with x1/x2 in result 
    for (int i = 0; i < 10; ++i) { 
     result += x1 * mul1[i] + x2 * mul2[i]; 
    } 

    return result; 
} 

Credo che sia funzionalmente equivalente alla seguente:

#include <cstdlib> 

int main(int argc, char** argv) { 
    int x1 = std::atoi(argv[1]); 
    int x2 = std::atoi(argv[2]); 

    return x1 * 50 + x2 * 46; 
} 

Eppure clang 3.7.1, gcc 5.3 e icc 13.0.1 sembrano essere in grado per rendere tale ottimizzazione, anche con -Ofast. (Nota come l'assemblaggio generato è molto diverso tra i compilatori!). Tuttavia, quando si rimuovono mul2 e x2 dall'equazione, clang è in grado di eseguire un'ottimizzazione simile, anche con -O2.

Cosa impedisce a entrambi i compilatori di ottimizzare il primo programma nel secondo?

+6

@buttiful buttefly In generale il funzionamento x1 * mul1 [i] può risultare in overflow, –

+0

Sono sorpreso che clang sia in grado di ottimizzare il ciclo quando si rimuove 'x2 * mul2 [i]' dall'equazione. Personalmente ritengo che non ci si debba aspettare nulla dall'ottimizzatore del compilatore; tutto ciò che viene ricevuto è un bonus! – iammilind

+6

L'overflow di @vlad è UB, quindi si può presumere che non si verifichi durante l'ottimizzazione. – Yakk

risposta

4

L'espressione completa è troppo complicata anche per clang. Se si divide poi tutto viene ottimizzato ancora:

int result1 = 0; 
int result2 = 0; 

for (int i = 0; i < 10; ++i) { 
    result1 += x1 * mul1[i]; 
    result2 += x2 * mul2[i]; 
} 

std::cout << (result1 + result2); 
2

Io non sono un programmatore compilatore quindi questo può essere solo una supposizione. IMHO, la risposta è parte della risposta di @ dlask e parte nell'osservazione che fa clang l'ottimizzazione quando rimuovi x2 e mul2 dall'espressione.

Il compilatore può ottimizzare tutto ciò che può fare. Ma penso anche che i compilatori di ottimizzazione siano già programmi enormi e complicati, in cui i bug possono avere conseguenze elevate perché sono alla base di quasi tutto il resto (l'interprete più attuale di Python è scritto in ... C)

Quindi lì deve essere un equilibrio tra l'efficienza dell'ottimizzatore e la sua complessità, e penso che questo programma di esempio sia oltre per GCC, e in giro per clang. Nulla impedisce loro di fare quell'ottimizzazione tranne che è troppo complicato per la versione corrente di quei compilatori.

+0

+1, ma non sono sicuro che sia una questione di complessità. Le ottimizzazioni sono create dagli sviluppatori del compilatore e, come ogni altro programmatore, anche loro devono dare la priorità. I programmi contengono raramente numeri codificati come nell'esempio, e un programmatore decente avrebbe comunque ottimizzato il codice a mano. Quindi avere l'ottimizzatore che gestisce questo caso particolare (e un milione di altri casi semplici che non corrispondono esattamente a un modello) è solo uno spreco di risorse. – eran

+1

@eran Sarei fortemente in disaccordo con te. A volte, l'ottimizzazione manuale riduce la leggibilità e quindi la manutenibilità. La bassa manutenibilità causa uno spreco di risorse molto più grande (tempo). Il dominio del compilatore è quello di produrre codice finale, quindi dovrebbe fare del suo meglio, con le informazioni disponibili, per produrre risultati ottimali. – GreenScape

Problemi correlati