2010-08-20 8 views
11

El siguiente código de prueba funciona correctamente en VS, ya sea con depuración o versión, y también en GCC. También funciona correctamente para ICC con depuración, pero no cuando la optimización está habilitada (-O2).¿Los compiladores pueden eliminar bucles infinitos como el compilador Intel C++ 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; 
} 

Se supone que parar en while(q.isEmpty()). Cuando -O2 habilitado en ICC (versión), sin embargo, comienza a "hacer algo" infinitamente.

Dado que este es el programa y isEmpty() deben ser evaluados como true de un solo subproceso, no puedo encontrar ninguna razón la CPI debe comportarse de esta manera? ¿Extraño algo?

+0

¿Ayuda si m_first y m_último se declaran como 'volátil'? No tengo acceso a ICC. – Chubsdad

+0

Otro pensamiento alocado: tiene que ver con el hecho de que% s no se especifica con printf. printf ("% s", "no debería llegar aquí \ r \ n");? – Chubsdad

+5

Relacionado: [¿Pueden los compiladores eliminar los bucles infinitos?] (Http://stackoverflow.com/questions/2178115/are-compilers-allowed-to-eliminate-infinite-loops) –

Respuesta

0

Su mejor opción es tomar el paso binario resultante y desarmar la función principal y ver qué ensamblado se generó. No dice que podrá ver un error, pero puede ver si se ha optimizado algo.

+0

No puedes. El código asm está optimizado y no puedes ver nada. – Samuel

+0

No estoy seguro de lo que eso significa. ¿Estás diciendo que desmontó el binario resultante y el ciclo while() desapareció? – linuxuser27

2

Seguro que suena como un error. Aquí hay una (bastante salvaje) adivinar lo que el razonamiento podría haber dado lugar a que ...

Después de procesos en línea, que ve:

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

y cualquier secuencia de do nothing repeatedly ; do something puede traducirse simplemente "hacer algo". Esto cae si la parte repetida es interminable (como en este caso). Pero tal vez no prueban su compilación en ejemplos que intencionalmente tienen bucle infinito ;-).

+0

La detección de bucles sin fin intencionales es básicamente el problema de detención, por lo que en su lugar suponen que, dado que no tiene efectos secundarios visibles, no hace nada y, por lo tanto, es inútil para el programa y puede eliminarse. Obviamente, si se completa IS es un sde-effect visible para nosotros, pero no para la máquina abstracta C/C++ definida por el estándar. Si desea el bucle, debe decirle al compilador que, de hecho, afecta el programa por, por ejemplo, volviendo volátil – Dan

-3

Creo que puede haber sido su versión de gcc. Recopilé tu prog bajo 4.4.2 y funcionó exactamente como debería.

+2

una de las variables leídas. Esto es icc, no gcc –

1

¿Alguna posibilidad de que el código real que compiló y ejecutó le faltara el punto y coma después de while(q.isEmpty())? Eso ciertamente daría como resultado que la siguiente línea sea llamada infinitamente.

+0

+1 por recordar algo similar – Chubsdad

+0

1. hay punto y coma 2. el mismo resultado con while (q.isEmpty()) {}, o mientras (q.isEmpty()) {true;} – Samuel

+0

A quien: ¿Era realmente necesario un voto negativo? He visto varios casos en SO donde el código publicado no era el código exacto que se usaba y donde el problema real se había omitido o reparado en la traducción. Solo quería ayudar a asegurarme de que esto no fuera el resultado de un error simple pero fácil de pasar por alto. (Después de todo, ¿no hemos perdido tiempo ocasionalmente en un error debido a algo así como un punto y coma equivocado?) – TheUndeadFish

10

Debido a que el bucle while (q.isEmpty()) ; no contiene instrucciones que puedan causar un efecto secundario externo visible, todo el bucle se está optimizando para que no exista. Es la misma razón por la que:

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

podría optimizarse fuera de la existencia, siempre y cuando no era ivolatile (tiendas a volatile objetos son parte de los efectos "visibles externamente" de un programa).

En el lenguaje C, en realidad es una manzana de la discordia sobresaliente sobre si se permite optimizar un bucle infinito de esta manera (no sé cuál es la situación con C++). Hasta donde yo sé, nunca se llegó a un consenso sobre este tema: las personas inteligentes y bien informadas han tomado partido por ambas partes.

+0

Esta podría ser la razón. El siguiente código funciona correctamente: static int A = 0; while (q.isEmpty()) {A = A + 1;} Pero no lo siguiente: static int A = 1; while (q.isEmpty()) {A;} – Samuel

+1

Interesante. Un bucle infinito que no hace nada: una buena oportunidad de optimización (y es comprensible por qué alguien puede estar en desacuerdo). – Suma

+0

Una cosa más: si while (true) se usa para while (q.isEmpty()), el código funciona correctamente. – Samuel

1

Como un pequeño lado, esta versión de icc hace lo que quiere. Es decir, nunca llama al doSomething().

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

estándar de C++ permite bucles sin efectos secundarios que ser eliminado, incluso si no terminan:

la impresión general es que es importante permitir la transformación potencialmente bucles sin terminación (por ejemplo, combinando dos bucles que iteran sobre el mismo conjunto potencialmente infinito , o eliminando un bucle sin efectos secundarios), incluso cuando ese no esté justificado en el caso en que el primer bucle nunca termina . http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm

Véase la discusión aquí: http://blog.regehr.org/archives/161

Cuestiones relacionadas