Clase digital 18. Generación de código.

Portada » Clase digital 18. Generación de código.
From above crop anonymous male programmer in black hoodie working on software code on contemporary netbook and typing on keyboard in workspace

Generación de código.

Introducción

¡Hola notable estudiante!

Mis felicitaciones por llegar hasta este momento de tu aprendizaje. Has llegado a la última clase del curso y siento mucho orgullo de tu gran participación y compromiso en este proceso formativo. Espero que cierres con broche de oro esta clase y no me resta otra cosa más que ofrecerte la bienvenida a ella.

En esta sesión aprenderemos sobre 

¡Empecemos y buena suerte!

Desarrollo del tema

Optimización de Código Intermedio:

El código intermedio se puede representar de manera gráfica para facilitar la optimización.

Bloques Básicos y Grafos de Flujo:

Particionar el código intermedio en bloques básicos.

  • El flujo de control puede solamente entrar al bloque básico por la primera instrucción del bloque. Entonces, no hay saltos en medio del bloque.
  • El control saldrá del bloque sin parada o ramificación, excepto posiblemente en la última instrucción del bloque.
  • La primera instrucción del código intermedio es un líder.

Los bloques básicos se encuentran desde un líder hasta antes de otro líder.

Los bloques básicos son los nodos de un grafo de flujo

Reglas para Encontrar Líderes:

  • La primera instrucción del código intermedio es un líder.
  • Cualquier instrucción que es objeto de un salto condicional o incondicional es un líder.
    Cualquier instrucción que siga inmediatamente a un salto condicional o incondicional es un líder.

Código para una Matriz Identidad

Grafo de Flujo y Bloques Básicos

Información de Vitalidad y Siguiente-Uso

  • Deseamos determinar para cada instrucción x = y + z los siguientes usos de x, y y z.
  • Algoritmo:
    • Agregar a la instrucción i la información encontrada en la tabla de símbolos sobre el siguiente-uso y vitalidad de x, y, y z.
    • En la tabla de símbolos, marcar x como “no vivo» y “sin siguiente-uso.“

En la tabla de símbolos, marcar y y z como “vivo» y los siguientes usos de y y z como i.

Representación de bloques básicos:

  • Hay un nodo en el DAG para cada valor inicial de las variables del bloque básico
  • Hay un nodo 
  • N asociado con cada instrucción s del bloque. Los hijos de N son aquellos nodos correspondientes a instrucciones que son las últimas definiciones, previas a s, de los operandos usados por s
  • Nodo N es etiquetado por el operador aplicado en s, y también adjuntado a N la lista de variables para las cuales es la última definición del bloque

Ciertos nodos son designados nodos de salida. Estos son los nodos cuyas variables están vivas al salir del bloque

Optimización de Código:

  • Se pueden eliminar subexpresiones locales comunes, o sea, instrucciones que calculan un valor que ya ha sido calculado.
  • Se puede eliminar código muerto, o sea, instrucciones que calculan un valor que nunca es usado.
  • Se pueden reordenar las instrucciones que no dependan entre sí; tal reordenamiento podría reducir el tiempo que un valor temporal necesita ser preservado en un registro.

Se pueden aplicar leyes algebraicas para reordenar operandos de instrucciones de tres direcciones, y algunas veces como resultado simplificar el cálculo.

Usos Principales de Registros:

  • En la mayoría de arquitecturas de máquina, algunos o todos de los operandos de una operación deben estar en los registros con el fin de realizar la operación.
  • Los registros son buenos almacenamientos temporales.
    • Lugares para contener el resultado de una sub-expresión mientras se evalúa una expresión mayor, o más en general, un lugar para contener una variable que se utiliza sólo dentro de un único bloque básico.
  • Los registros se utilizan a menudo para ayudar a la gestión del almacenamiento en tiempo de ejecución.

por ejemplo, para gestionar la pila de tiempo de ejecución, incluyendo el mantenimiento de los punteros de pila y, posiblemente, los elementos superiores de la pila en sí.

Característica de Optimizaciones de Mirilla:

  • Eliminación de Instrucciones Redundantes.
  • Optimizaciones de Flujo de Control.
  • Simplificaciones Algebraicas.

Uso de frases idiomáticas de máquina.

Eliminación de Instrucciones Redundantes:

LD a, R0
ST R0, a
if debug == 1 goto L1
goto L2
L1: print debugging information
L2:

Optimizaciones de Control de Flujo:

goto L1

L1: goto L2
Puede ser reemplazado por:
goto L2

L1: goto L2

if a<b goto L1

L1: goto L2
Puede ser reemplazado por:
if a<b goto L2

L1: goto L2

Simplificaciones Algebraicas:

  • x=x+0
  • x=x*1

Asignación de Registro:

  • Asignación de Registro Global
  • Conteos de Uso
  • Asignación de Registro para bucles externos

Asignación de Registro por coloración de Grafo

Conclusión

Para recordar:

¡Has llegado al final de la última clase del curso, muchas felicidades! Ha sido un gozo compartir contigo este trayecto formativo. Deseo que el curso haya cumplido tus expectativas y encuentres satisfacción con los temas abordados, así como con tu desempeño y compromiso. Para concluir de forma correcta, te invito a realizar la tarea asignada y mandarla como corresponde. Espero encontrarte nuevamente, ¡hasta pronto!

Fuentes de información