2012-04-18 21 views
8

Es fácil ver que:Operaciones lógicas en operaciones de módulo múltiple optimizadas?

(i % 3 == 0) && (i % 5 == 0) 

se puede simplificar a:

(i % 15 == 0) 

mirando Sin embargo, en la salida del CCG, al parecer esto no se hace incluso a altos niveles de optimización.

¿Los compiladores realizan este tipo de optimizaciones, o hay una buena razón por la cual esas dos pruebas no son semánticamente equivalentes?

Editar: En respuesta a los que dicen que este es un caso marginal, el siguiente es un caso similar:

(i < 3) && (i < 5) 

Cualquier número menor que 3, debe ser siempre inferior a 5. Segunda prueba es redundante.

También me gustaría añadir lo siguiente en respuesta a la respuesta que el compilador no puede saber si está afectado el medio ambiente ... Mira este código:

void foo(void) 
{ 
    int i; 
    for (i = 0; i <= 10; i++) 
    { 
     if (i > 20) 
     { 
      puts("Hi"); 
     } 
    } 
} 

función entera se reduce a "REPZ ret "por GCC con -O2. Eso es mucho más complejo que cualquier cosa de la que estoy hablando.

+1

Supongo que es para garantizar la evaluación de cortocircuitos ... – Anycorn

+0

¿Los compiladores en general comprueban si hay múltiples comparaciones en la misma variable para la optimización? Parece un caso marginal ... – trutheality

+2

@Anycorn, ¿Estás diciendo que evaluar 'i' puede tener efectos secundarios, y el compilador no sabe si lo hace o no? – ikegami

Respuesta

5

Ignora todas las respuestas tontas diciendo que esto es terriblemente difícil/imposible de hacer para un compilador. No veo ninguna razón por la cual sería difícil, pero, presumiblemente, nadie pensó en hacerlo o pensó que sería lo suficientemente importante como para optimizarlo. Si desea una respuesta mejor que esta, deberá informarla en el rastreador de errores de GCC como una solicitud de mejora y ver lo que dicen los desarrolladores.

+0

Creo que te refieres a * in * suficientemente. Pero sí, estoy de acuerdo contigo. – Matt

+1

Mi gramática era correcta. El sujeto sigue siendo "nadie", lo que proporciona la semántica negativa. :-) –

3

Su ejemplo es bastante simple y de hecho es fácil de condensar en una sola operación. El caso general de una declaración como esta, sin embargo, no es tan simple. Tome la siguiente, por ejemplo:

((++i) % 3 == 0) && ((++i) % 5 == 0) 

Esta variación no puede ser simplificado a una sola operación de módulo con la misma facilidad (sé que esta afirmación tiene todo tipo de otros problemas con él, pero el punto es que el problema ISN' Es tan simple cuando estás usando otra cosa que no sea una simple referencia de variable). Por lo general, los compiladores no verán que su caso solo involucre variables simples y que lo optimicen de manera diferente que el caso general; intentan mantener las optimizaciones consistentes y predecibles siempre que sea posible.

Actualización: Los casos adicionales que usted aumentó a su caída pregunta en una clase completamente diferente de la optimización de su fragmento de código original. Ambos están optimizados porque son código inalcanzable, y se pueden probar como tales en tiempo de compilación. Su pregunta original implicó volver a escribir dos operaciones en una única operación equivalente que es única del original. Los dos fragmentos que ha agregado no vuelven a escribir el código existente, solo eliminan el código que nunca se puede ejecutar. Los compiladores suelen ser muy buenos para identificar y eliminar el código muerto.

La optimización que está buscando es una forma de reducción matemática de la fuerza. La mayoría de los compiladores ofrecen cierto nivel de optimizaciones de MSR, aunque el nivel de detalle que obtengan variará según el compilador y las capacidades de la plataforma de destino. Por ejemplo, un compilador dirigido a una arquitectura de CPU que no tiene una instrucción de módulo (lo que significa que se debe usar en su lugar una función de biblioteca potencialmente larga) puede optimizar afirmaciones como esta de forma más agresiva. Si la CPU objetivo tiene compatibilidad con el módulo de hardware, el escritor del compilador podría considerar que las dos o tres instrucciones guardadas son demasiado pequeñas como para que valga la pena el tiempo y el esfuerzo necesarios para implementar y probar las mejoras de optimización. He visto esto en el pasado con ciertas operaciones que se pueden hacer en una sola instrucción en una CPU x86 (por ejemplo) pero requeriría docenas de instrucciones en una CPU RISC.

+0

No estoy de acuerdo. Los compiladores son buenos para encontrar subexpresiones comunes (de las cuales simplemente 'i' es un caso trivial) y optimizar su uso. –

+1

@R ..- Sin embargo, esto no se clasifica exactamente como una sub-expresión común. Las optimizaciones de CSE buscan un subcomponente que varias declaraciones tienen en común y luego utilizan un valor precaché en lugar de volver a calcular la expresión varias veces. Aquí, la única parte común es 'i%', que no es una declaración completa y no es calculable. Lo que el OP está pidiendo está más estrechamente relacionado con la familia de optimizaciones de "reducción matemática de la fuerza". – bta

+0

Además de todo esto, recuerde que el operador '&&' introduce un punto de secuencia (para operación de "cortocircuito"). Si el lado izquierdo se evalúa como cero, el lado derecho no se ejecuta en absoluto. Debido a los muchos efectos secundarios posibles involucrados, es probable que los compiladores sean muy reacios a optimizar un punto de secuencia. Parece fácil para casos simples como este, pero como un problema general, es mucho más difícil de hacer. – bta

1

Honestamente, ese es un caso muy específico. Si se cambia alguna parte de la ecuación, la optimización ya no se aplicaría. Creo que se trata de costos versus ganancias, y el costo de implementar esta optimización (mayor tiempo de compilación, mayor dificultad de mantenimiento) supera los beneficios (algunas operaciones menos rápidas en circunstancias excepcionales).

En general, la refacturación matemática no se puede aplicar debido a la limitación de precisión y la posibilidad de desbordamiento. Aunque no creo que sea un problema aquí.