Compiladores

Generación de código

Introducción
• La fase final de nuestro modelo de compilador es el generador de código • Toma por entrada una RI del fuente y produce su equivalente en código objeto • Las técnicas que veremos son independientes de si se realiza o no optimización

se imponen en un generador de código son muy demandantes • El código generado debe ser correcto y de alta calidad (debe hacer uso efectivo de los recursos de la máquina objeto) • El generador.Introducción • Los requerimientos que. tradicionalmente. además. debe ser eficiente .

se utilizan heurísticas que generan código bueno (aunque probablemente no óptimo) .Introducción • El problema de generar código óptimo es no decidible • En la práctica.

Aspectos generales • • • • • • Entrada al generador de código (RI) Programas objeto Administración de memoria Selección de instrucciones Adjudicación de registros Elección de orden de evaluación .

Entrada al generador de código • La entrada consiste en la RI del código fuente. junto con la información de la tabla de símbolos • La TS se utiliza para determinar las direcciones en tiempo de ejecución de los objetos de datos denotados por los nombres en la RI • Asumimos que la RI es de “suficiente bajo nivel” con tipos de datos que se pueden mapear razonablemente a la arquitectura objeto . producida por el frontend.

. y demás • Asumimos que no hay errores semánticos obvios (Ej.Entrada al generador de código • Asumimos que el chequeo de tipos ya fue realizado. intentar indizar un arreglo con un punto flotante) . con la adecuada inserción de operadores de cambio de tipos.

el chequeo se realiza a la vez que la generación de código) .Entrada al generador de código • Esta fase se basa en la asunción de que la RI no tiene errores (aunque en algunos compiladores.

Código objeto • La salida del generador es el código o programa objeto. el cual puede tomar distintas formas: – código máquina absoluto – código máquina reubicable – código assembler .

Luego se unen (linking) y se cargan .Código objeto • Producir código máquina absoluto como salida conlleva la ventaja de que puede ser ubicado en un lugar fijo de memoria y ejecutado inmediatamente • Código reubicable (también llamado módulo objeto) permite tener módulos que se compilan por separado.

• Si la máquina objeto no se hace cargo de la reubicación.Código objeto • En este caso se gana mucha flexibilidad en función del trabajo que conlleva la unión y carga. el compilador debe producir información explícita para el linker .

Código objeto • Finalmente. Podemos generar instrucciones simbólicas y usar las macros de assembler como ayudas. • Finalmente. facilita la optimización “a mano” del código generado. • El precio es que aparece una etapa final de ensamblado . producir código assembler como salida facilita el proceso de compilación.

Administración de memoria • Consiste en determinar la posición de memoria en la que los diferentes símbolos del programa almacenan la información • Depende de la estrategia utilizada para la gestión de memoria. el mecanismo puede variar .

Selección de instrucciones • La naturaleza del conjunto de instrucciones de la máquina objeto. entonces se necesitan estrategias alternativas . • Si la máquina objeto no soporta cada tipo de datos de forma uniforme. determina la dificultad de la selección de instrucciones • La uniformidad y completitud del conjunto de instrucciones son factores muy importantes.

R0 – MOV R0. para cada tipo de sentencia en C3D podemos diseñar un esqueleto de código que muestra el código objeto a generar para esa construcción • Ej.Selección de instrucciones • Si no nos interesa la eficiencia. R0 – ADD Z.: x:=y+z – MOV Y. X • Esto genera código pobre .

R0 ADD c. a MOV a. d  redundante?  redundante? . R0 MOV R0. R0 MOV R0. RO ADD e.Selección de instrucciones • Por ejemplo: – a := b + c – d := a + e • Se traduce a – – – – – – MOV b.

es un problema muy complejo. . • Para los casos no triviales. INC vs MOV .MOV).Selección de instrucciones • La calidad del código generado se mide en función de – Tamaño – Velocidad • En función de la variedad de instrucciones uno puede seleccionar la instrucción más performante (ej.ADD .

la adjudicación eficiente de registros tiene un gran impacto en la performance .Asignación de registros • Operar sobre registros es más rápido y eficiente que operar sobre memoria • Por ello.

se seleccionan el conjunto de variables que vivirá en registros en un punto del programa. se elige el registro específico para cada variable. – Durante la (posterior) asignación de registros (assignation).Asignación de registros • El uso de registros puede dividirse en dos subproblemas: – Durante la reserva de registros (allocation). .

Orden de evaluación • El orden en que algunas computaciones se llevan a cabo puede afectar la eficiencia del código objeto • Algunos ordenes requieren menos registros para almacenar valores intermedios • Seleccionar el orden óptimo es también NP-completo .

Orden de evaluación • El orden en que algunas computaciones se llevan a cabo puede afectar la eficiencia del código objeto • Algunos ordenes requieren menos registros para almacenar valores intermedios • Seleccionar el orden óptimo es también NP-completo .