Influencia de los compiladores de lenguajes de alto nivel
Las prestaciones de los actuales computadores al ejecutar un programa dependen significativamente del compilador que se utilice. Cuando se diseña el repertorio de instrucciones se tiene en mente en todo momento la tecnología de diseño de compiladores.
Las decisiones arquitectónicas afectan directamente a la complejidad de diseño de un buen compilador.
Un compilador consta de una serie de etapas, las cuales transforman representaciones abstractas de alto nivel, en representaciones de más bajo nivel, hasta llegar al repertorio de instrucciones.
Un compilador busca en primer lugar la exactitud de la traducción (mantenimiento de la semántica del programa en la transformación), en segundo lugar la velocidad del código generado, en tercer lugar el tamaño del código, en cuarto lugar la velocidad del compilador, y en quinto lugar el soporte a la depuración.
Desde el punto de vista del rendimiento que ahora nos ocupa, la velocidad del código generado es el factor a optimizar
Las optimizaciones realizadas por los compiladores modernos podemos resumirlas en las siguientes:
1. Optimización de alto nivel: realizadas en el código fuente
• Integración de procedimientos: sustituye la llamada a un procedimiento por el cuerpo de éste (expansión de macros).
2. Optimizaciones locales: afectan a fragmentos de código lineal (sin bifurcaciones)
• Eliminación de subexpresiones comunes
• Propagación de constantes
• Reducción del tamaño de la pila en la evaluación de expresiones reorganizando su estructura
3. Optimizaciones globales: afectan al programa completo, son más complejas de implementar.
• Optimización de bucles
• Eliminación de subexpresiones comunes de alcance global (incluyendo saltos)
• Propagación de copias: sustituye todas las instancias de una variable asignada.
4. Optimización del uso de registros: es una de las que reporta mayor incremento de rendimiento. La estudiaremos con más detalle a continuación.
5. Optimizaciones dependientes de la máquina: Aprovechan el conocimiento de las arquitecturas específicas.
• Multiplicación por una constante y sustitución por sumas y desplazamientos
• Elección del desplazamiento más corto en los saltos
Por último conviene destacar que las dos ayudas más importantes que la arquitectura de un procesador puede prestar al diseño del compilador son:
• Regularidad del repertorio, es decir, ortogonalidad de sus elementos para simplificar la generación de código
• Proporcionar funciones primitivas, no soluciones codificadas en las instrucciones, pues estas resultan difícil de utilizar cuando el caso se aparta ligeramente del que originó su diseño.
Fuente: Estructura de Computadores, Facultad de Informática, UCM