2010-08-20 9 views
11

Il seguente codice di test funziona correttamente in VS con debug o release e anche in GCC. Funziona correttamente anche per ICC con debug, ma non quando l'ottimizzazione è abilitata (-O2).I compilatori sono autorizzati a rimuovere loop infiniti come Intel C++ Compiler con -O2?

#include <cstdio> 

class tClassA{ 
public: 
    int m_first, m_last; 

    tClassA() : m_first(0), m_last(0) {} 
    ~tClassA() {} 

    bool isEmpty() const {return (m_first == m_last);} 
    void updateFirst() {m_first = m_first + 1;} 
    void updateLast() {m_last = m_last + 1;} 
    void doSomething() {printf("should not reach here\r\n");} 
}; 

int main() { 
    tClassA q; 
    while(true) { 
    while(q.isEmpty()) ; 
    q.doSomething(); 
    } 
    return 1; 
} 

Si suppone di fermarsi allo while(q.isEmpty()). Quando -O2 è abilitato in ICC (release), tuttavia, inizia a "fare qualcosa" all'infinito.

Dal momento che questo è a thread singolo programma eisEmpty() dovrebbero essere valutati come true, riesco a trovare alcun motivo per il CPI dovrebbe comportarsi in questo modo? Mi manca qualcosa?

+0

Aiuta se m_first e m_last sono dichiarate come 'volatili'? Non ho accesso a ICC. – Chubsdad

+0

Un altro pensiero selvaggio: ha a che fare con il fatto che% s non è specificato con printf. printf ("% s", "non dovrebbe raggiungere qui \ r \ n") ;? – Chubsdad

+5

Correlati: [I compilatori sono autorizzati ad eliminare i loop infiniti?] (Http://stackoverflow.com/questions/2178115/are-compilatori-allontanati-per-eliminare-infinite-loops) –

risposta

0

La soluzione migliore è quella di eseguire il passaggio binario risultante in esso e disassemblare la funzione principale e vedere quale gruppo è stato generato. Non dicendo che sarai in grado di vedere un bug, ma puoi vedere se qualcosa è stato ottimizzato.

+0

Non è possibile. Il codice asm è ottimizzato via tutto e non puoi vedere nulla. – Samuel

+0

Non sono sicuro di cosa significhi. Stai dicendo che hai smontato il binario risultante e il ciclo while() era sparito? – linuxuser27

2

Sembra proprio un bug. Ecco un (abbastanza selvaggio) indovinate su cosa il ragionamento potrebbe avere portare ad esso ...

Dopo inlining, vede:

while (q.m_first == q.m_last) /* do nothing */ ; 
do_something(); 

e qualsiasi sequenza di do nothing repeatedly ; do something può essere tradotto semplicemente "fare qualcosa". Questo cade se la parte ripetuta è infinita (come in questo caso). Ma forse non testano la loro compilazione su esempi che hanno intenzionalmente loop infiniti ;-).

+0

Rilevare il loop infinito intenzionale è fondamentalmente il problema dell'arresto, così invece assumono che, poiché non ha effetti collaterali visibili, non fa nulla e quindi è inutile per il programma e può essere rimosso. Ovviamente, indipendentemente dal fatto che completi o meno un effetto sde visibile per noi, ma non per la macchina astratta C/C++ definita dallo standard. Se vuoi il ciclo, devi dire al compilatore che lo fa, anzi, influenza il programma, per exmaple, rendendo volatile una delle variabili di lettura – Dan

-3

Penso che potrebbe essere stata la tua versione di gcc. Ho compilato il tuo prog sotto 4.4.2 e ha funzionato esattamente come dovrebbe.

+2

Questo è icc, non gcc –

1

In caso il codice effettivo che è stato creato e in esecuzione mancasse del punto e virgola dopo while(q.isEmpty())? Ciò comporterebbe sicuramente il fatto che la riga successiva venga chiamata infinitamente.

+0

+1 per ricordarmi di qualcosa di simile – Chubsdad

+0

1. c'è il punto e virgola 2. lo stesso risultato con while (q.isEmpty()) {}, o while (q.isEmpty()) {true;} – Samuel

+0

Per chiunque: il down era davvero necessario? Ho visto un certo numero di casi su SO in cui il codice pubblicato non era il codice esatto usato e dove il problema reale era stato omesso o risolto nella traduzione. Volevo solo assicurarmi che questo non fosse il risultato di un errore semplice ma facile da trascurare. (Dopotutto, non tutti abbiamo saltuariamente perso tempo a causa di qualcosa di simile a un punto e virgola errato?) – TheUndeadFish

10

Poiché il ciclo while (q.isEmpty()) ; non contiene istruzioni che possano mai causare un effetto collaterale visibile esternamente, l'intero ciclo viene ottimizzato al di fuori dell'esistenza. È la stessa ragione:

for (int i = 0; i < 10; i++) 
    ; 

potrebbe essere ottimizzato di esistere, purché i non era volatile (depositi a volatile oggetti fanno parte degli effetti "visibili esternamente" di un programma).

Nel linguaggio C, è in realtà un enorme problema di contesa sul fatto che un loop infinito possa essere ottimizzato in questo modo (non so quale sia la situazione con C++). Per quanto ne so, non è mai stato raggiunto un consenso su questo tema: persone intelligenti e competenti hanno preso entrambe le parti.

+0

Questa potrebbe essere la ragione. Il seguente codice funziona correttamente: static int A = 0; while (q.isEmpty()) {A = A + 1;} Ma non il seguente: static int A = 1; while (q.isEmpty()) {A;} – Samuel

+1

Interessante. Un ciclo infinito che non fa nulla - bella opportunità di ottimizzazione (ed è comprensibile perché qualcuno possa non essere d'accordo). – Suma

+0

Un'altra cosa: se while (true) viene usato per while (q.isEmpty()), il codice funziona correttamente. – Samuel

1

Come una leggera parentesi, questa versione di ICC fa quello che vuoi. Cioè, non chiama mai doSomething().

[9:41am][[email protected] /tmp] icc --version 
icc (ICC) 11.0 20081105 
1

serie La C++ consente loop senza effetti collaterali per essere rimosso, anche se non terminano:

si ritiene in generale che è importante permettere trasformazione potenzialmente loop non terminanti (ad esempio unendo due loop che itera sullo stesso set potenzialmente infinito o eliminando un ciclo senza effetti collaterali di ), anche quando tale potrebbe non essere giustificato in altro modo nello caso in cui termina il primo ciclo mai . http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm

Vedi la discussione qui: http://blog.regehr.org/archives/161

Problemi correlati