Vous êtes sur la page 1sur 46

Cap tulo 7 Generacin de cdigo o o intermedio.

Optimizacin o
Bibliograf a: Aho, A.V., Sethi, R., Ullman, J.D. (1990), Compiladores: principios, tcnicas y herramientas, Tema 8, 9, 10 (pag. 478e 666). Louden, K.C. (1997), Compiler Construction: Principles and Practice, Tema 8, pginas: 398-481. a 1. Introduccin. o 2. Tipos de representaciones intermedias: Cdigo de 3-direcciones. o 3. Cdigo intermedio como un atributo sintetizado. o 4. Generacin de cdigo para expresiones y sentencias de cono o trol: a) Proposiciones de asignacin. o b) Expresiones aritmticas. e c) Expresiones booleanas. d ) Sentencias de control. e) Funciones. 5. Optimizacin de cdigo: o o a) Bloques bsicos y optimizacin local. a o
215

216CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

b) Eliminacin de subexpresiones comunes. o c) Eliminacin de cdigo muerto. o o d ) Transformaciones aritmticas. e e) Empaquetamiento de variables temporales. f ) Mejoras en lazos.

7.1.

Introduccin o

Como se coment en el primer cap o tulo el proceso de la compilacin se desglosa en dos partes: la parte que depende slo del o o lenguaje fuente (etapa inicial o front-end ) y la parte que depende slo del lenguaje objeto (etapa nal o back-end). o Etapa inicial: corresponde con la parte de anlisis (lxico, a e sintctico y semntico). a a Etapa nal: corresponde con la parte de s ntesis (generacin o de cdigo). o La etapa inicial traduce un programa fuente a una representacin o intermedia a partir de la cual la etapa nal genera el cdigo obo jeto. De esta forma, los detalles que tienen que ver con las caracter sticas del lenguaje objeto (cdigo ensamblador, cdigo mquina abo o a soluto o relocalizable, . . . ), la arquitectura de la mquina (nmero a u de registros, modos de direccionamiento, tamao de los tipos de n datos, memoria cache, ...), el entorno de ejecucin (estructura de o registros y memoria de la mquina donde se va a ejecutar el proa grama . . . ) y el sistema operativo se engloban en la etapa nal y se aislan del resto. La generacin de cdigo es la tarea ms complicada de un como o a pilador. Las ventajas de utilizar esta representacin intermedia, o independiente de la mquina en la que se va a ejecutar el prograa ma, son: Se puede crear un compilador para una nueva mquina disa tinta uniendo la etapa nal de la nueva mquina a una etapa a inicial ya existente. Se facilita la redestinacin. o

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES217

Se puede aplicar, a la representacin intermedia, un optio mador de cdigo independiente de la mquina. o a La gura 7.1 muestra las dos etapas y como se relacionan entre s a travs de la representacin intermedia. e o
Programa fuente ETAPA INICIAL ETAPA FINAL Analizador Lxico Componentes lxicos Analizador Sintctico Arbol Sintctico Analizador Semntico Cdigo Intermedio Optimizador de Cdigo mquina Generador de cdigo mquina

Cdigo mquina

Optimizador de cdigo intermedio

Figura 7.1: Etapa inicial y nal de un compilador

En este cap tulo veremos cmo traducir las construcciones de los o lenguajes de programacin como: las declaraciones, asignaciones o y proposiciones de ujo de control a una representacin intermeo dia. La mayor parte de las traducciones de estas proposiciones se pueden implantar durante el anlisis sintctico utilizando las a a tcnicas de traduccin vistas en en el diseo de esquemas de trae o n duccin dirigidos por la sintaxis (ETDS). o

7.2.

Tipos de representaciones intermedias: el cdigo de 3-direcciones o

Una representacin intermedia es una estructura de datos que o representa al programa fuente durante el proceso de la traduccin a cdigo objeto. Hasta ahora hemos usado el rbol de anlio o a a

218CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

sis sintctico como representacin intermedia, junto con la tabla a o de s mbolos que conten informacin sobre los nombres (varia o ables, constantes, tipos y funciones) que aparec en el programa an fuente. Aunque el rbol de anlisis sintctico es una representacin vlia a a o a da, no se parece ni remotamente al cdigo objeto, en el que slo o o se emplean saltos a direcciones en memoria en vez de construcciones de alto nivel, como sentencias if-then-else. Es necesario generar una nueva forma de representacin intermedia. A o esta representacin intermedia, que se parece al cdigo objeto o o pero que sigue siendo independiente de la mquina, se le llama a cdigo intermedio. o El cdigo intermedio puede tomar muchas formas. Todas ellas se o consideran como una forma de linearizacin del rbol sintctio a a co, es decir, una representacin del rbol sintctico de forma seo a a cuencial. El cdigo intermedio ms habitual es el cdigo de 3o a o direcciones. El cdigo de tres direcciones es una secuencia de proposiciones o de la forma general x = y op z donde op representa cualquier operador; x,y,z representan variables denidas por el programador o variables temporales generadas por el compilador. y,z tambin pueden representar cone stantes o literales. op representa cualquier operador: un operador aritmtico de punto jo o otante, o un operador lgico sobre e o datos booleanos. No se permite ninguna expresin aritmtica compuesta, pues slo o e o hay un operador en el lado derecho. Por ejemplo, x+y*z se debe traducir a una secuencia, donde t1 , t2 son variables temporales generadas por el compilador. t1 = y z t2 = x + t1 Las expresiones compuestas y las proposiciones de ujo de control se han de descomponer en proposiciones de este tipo, deniendo un conjunto sucientemente amplio de operadores. Se le llama cdigo de 3-direcciones porque cada proposicin contiene, en el o o

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES219

caso general, tres direcciones, dos para los operandos y una para el resultado. (Aunque aparece el nombre de la variable, realmente corresponde al puntero a la entrada de la tabla de s mbolos de dicho nombre). El cdigo de tres direcciones es una representacin linealizada o o (de izquierda a derecha) del rbol sintctico en la que los noma a bres temporales corresponden a los nodos internos. Como estos nombres temporales se representan en la memoria no se especica ms informacin sobre ellos en este tipo de cdigo. Normalmente a o o se asignarn directamente a registros o se almacenarn en la tabla a a de s mbolos. 2*a+b-3

+
t1

t3

* 2
Cdigo de 3-direcciones: o t1 = 2 * a t2 = b - 3 t3 = t1 + t2

a b

t2

7.2.1.

Tipos de proposiciones de 3-direcciones

La forma de cdigo de 3-direcciones que hemos visto hasta ahoo ra es insuciente para representar todas las construcciones de un lenguaje de programacin (saltos condicionales, saltos incondio cionales, llamadas a funciones, bucles, etc), por tanto es necesario introducir nuevos operadores. El conjunto de proposiciones (operadores) debe ser lo sucientemente rico como para poder implantar las operaciones del lenguaje fuente. Las proposiciones de 3-direcciones van a ser en cierta manera anlogas al cdigo ensamblador. Las proposiciones pueden tener a o etiquetas simblicas y existen instrucciones para el ujo de cono trol (goto). Una etiqueta simblica representa el o ndice de una proposicin de 3-direcciones en la lista de instrucciones. o

220CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Las proposiciones de 3-direcciones ms comunes que utilizaremos: a 1. Proposiciones de la forma x = y op z donde op es un operador binario aritmtico, lgico o relacional. e o 2. Instrucciones de la forma x = op y, donde op es un operador unario (operador negacin lgico, menos unario, opero o adores de desplazamiento o conversin de tipos). o 3. Proposiciones de copia de la forma x = y, donde el valor de y se asigna a x. 4. Salto incondicional goto etiq. La instruccin con etiqueta o etiq es la siguiente que se ejecutar. a 5. Saltos condicionales como if false x goto etiq. 6. param x y call f para apilar los parmetros y llamadas a a funciones (los procedimientos se consideran funciones que no devuelven valores). Tambin return y, que es opcional, e para devolver valores. Cdigo generado como parte de una o llamada al procedimiento p(x 1,x 2,...,x n). param x1 param x2 ... param xn call p,n 7. Asignaciones con ndices de la forma x = y[i], donde se asigna a x el valor de la posicin en i unidades de memoria o ms all de la posicin y. O tambin x[i] = y . a a o e 8. Asignaciones de direcciones a punteros de la forma x = &y (el valor de x es la direccin de y), x = *y (el valor de x se o iguala al contenido de la direccin indicada por el puntero o y) *x = y (el objeto apuntado por x se iguala al valor de o y). Ejemplo. Consideremos el cdigo que calcula el factorial de un o nmero. La tabla 7.1 muestra el cdigo fuente y el cdigo de 3u o o direcciones. Existe un salto condicional if false que se usa para

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES221

traducir las sentencias de control if-then, repeat-until que contiene dos direcciones: el valor condicional de la expresin o y la direccin de salto. La proposicin label slo tiene una dio o o reccin. Las operaciones de lectura y escritura, read, write, o con una sola direccin. Y una instruccin de parada halt que no o o tiene direcciones.
read x; if 0<x then fact:=1; repeat fact:=fact*x; x:=x-1; until x=0; write fact; end; read x t1 = 0 < x if false t1 goto L1 fact=1 label L2 t2=fact * x fact=t2 t3=x-1 x=t3 t4=x==0 if false t4 goto L2 write fact label L1 halt Cuadro 7.1: Cdigo fuente y cdigo de 3-direcciones para el clculo del factorial o o a

222CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.2.2.

Implementacin de cdigo de tres direcciones o o

Una proposicin de cdigo de 3-direcciones se puede implantar o o como una estructura tipo registro con campos para el operador, los operandos y el resultado. La representacin nal ser entonces o a una lista enlazada o un vector de proposiciones. Implementacin mediante cudruplos o a Un cudruplo es una estructura tipo registro con cuatro campos a que se llaman (op, result, arg1, arg2). El campo op contiene un cdigo interno para el operador. o Por ejemplo, la proposicin de tres direcciones x = y + z se o representa mediante el cudruplo (ADD, x,y, z). Las proposia ciones con operadores unarios no usan el arg2. Los campos que no se usan se dejan vac o un valor NULL. Como se necesitan os cuatro campos se le llama representacin mediante cudruplos. o a Una posible implantacin del programa que calcula el factorial o mediante cudruplos se muestra ahora en la parte izquierda de la a tabla 7.2.

7.2. TIPOS DE REPRESENTACIONES INTERMEDIAS: EL CODIGO DE 3-DIRECCIONES223 (a) Cudruplos a (read,x,,) (isbigger,t1,x,0) (if false,t1,L1,) (assign,fact,1,) (label,L2,,) (mult,t2,fact,x) (assign,fact,t2,) (sub,t3,x,1) (assign,x,t3,) (isequal,t4,x,0) (if false,t4,L2,) (write,fact,,) (label,L1,,) (halt,,,) Cuadro 7.2: Cdigo de 3-direcciones mediante: (a) cudruplos y (b) tripletes o a (b) Tripletes (0) (read,x,) (1) (isbigger,x,0) (2) (if false, (1), (11)) (3) (assign, fact,1) (4) (mult, fact,x) (5) (assign, (4), fact) (6) (sub, x,1) (7) (assign, (6), x) (8) (isequal, x, 0) (9) (if false, (8),(4)) (10) (write,fact,) (11) (halt,,)

Implementacin mediante tripletes o Para evitar tener que introducir nombres temporales en la tabla de s mbolos, se hace referencia a un valor temporal segn la posiu cin de la proposicin que lo calcula. Las propias instrucciones o o representan el valor del nombre temporal. La implantacin se hace o mediante registros de slo tres campos (op, arg1, arg2). o La parte derecha de la tabla 7.2 muestra la implantacin mediante o tripletes del clculo del factorial. Los nmeros entre parntesis a u e representan punteros dentro de la lista de tripletes, en tanto que los punteros a la tabla de s mbolos se representan mediante los nombres mismos. En la notacin de tripletes se necesita menor espacio y el como pilador no necesita generar los nombre temporales. Sin embargo, en esta notacin, trasladar una proposicin que dena un valo o or temporal exige que se modiquen todas las referencias a esa proposicin. Lo cual supone un inconveniente a la hora de optio mizar el cdigo, pues a menudo es necesario cambiar proposiciones o de lugar.

224CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

A partir de ahora nos vamos a centrar en la notacin de cudruo a plos, que es la que se implantar en la prctica 3. La gura 7.2 a a a continuacin muestra en cdigo C como se podr implantar la o o a estructura de datos para los cudruplos: a
typedef enum {assign, add, mult,if false, goto, label, read, write, isequal, . . . } OpKind; typedef struct { int val;// para valores char *name;// para identicadores de variables } Address; typedef struct { OpKind op; Address result, arg1, arg2; } Quad; Figura 7.2: Posible implantacin en C de la estructura cudruplo o a

Por simplicidad se podrian considerar los campos result, arg1, arg2 como punteros a caracter. En esta implantacin slo se pero o mite que un argumento represente una constante entera o una cadena ( la cadena representa el nombre de un temporal o una variable de la tabla de s mbolos). Una alternativa a almacenar nombres en el cudruplo es almacenar punteros a la tabla de s a mbolos, con lo que se evita tener que hacer operaciones de bsqueda en u un procesado posterior.

7.3.

Cdigo intermedio como un atributo sino tetizado

El cdigo intermedio puede ser considerado como un atributo sino tetizado. El cdigo intermedio es visto como una cadena de caro acteres y se puede disear un esquema de traduccin dirigido por n o la sintaxis (ETDS) que genere dicho cdigo al recorrer el rbol de o a anlisis sintctico en orden postjo. a a Consideremos como ejemplo la siguiente gramtica simplicada a que genera expresiones aritmticas. Dada la expresin E E1 + e o

7.3. CODIGO INTERMEDIO COMO UN ATRIBUTO SINTETIZADO 225

E2 se calcula el valor del no-terminal E en un nombre temporal t. Por el momento, se crea un nuevo nombre cada vez que se necesita. Ms tarde veremos un sencillo mtodo para reutilizar a e los nombres temporales. Cada no-terminal tiene dos atributos: E.lugar, nombre temporal que contendr el valor de E, a (t1 , t2 , . . .). E.cod, serie de todas las proposiciones de cdigo de 3-direcciones o que calculan E. Ambos atributos son sintetizados. La funcin nuevotemp() geno era nombres distintos t1 , t2 , ... cada vez que es llamada. Las llaves indican una instruccin de cdigo de 3-direcciones. El o o s mbolo // representa la concatenacin de los trozos de cdigo. o o
Produccin o S id := E E E1 + E2 E (E1 ) E id E num Regla Semntica a S.cod = E.cod//{lexema(id) = E.lugar} E.lugar = nuevotemp(); E.cod = E1 .cod//E2 .cod//{E.lugar = E1 .lugar + E2 .lugar} E.lugar = E1 .lugar E.cod = E1 .cod E.lugar = lexema(id) E.cod = E.lugar = lexema(num); E.cod = Cuadro 7.3: ETDS para expresiones aritmticas e

Veamos el ejemplo x=x+3+4. La gura 7.3 muestra el rbol sintctia a co. El cdigo de 3-direcciones correspondiente es: o
t1 = x + 3 t2 = t1 + 4 x = t2

226CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION


cod=t1=x+3 t2=t1+4 x=t2

S
cod=t1=x+3 E lugar=t2 t2=t1+4

id (x)

cod=t1=x+3 E lugar=t1

cod= E lugar=4

cod=

E lugar=x + id (x)

cod= E lugar=3 num

(4) num (3)

Figura 7.3: Arbol sintctico para el ejemplo x=x+3+4 a

Reutilizacin de los nombres temporales o Hasta ahora se ha supuesto que la funcin nuevotemp() genera o un nombre temporal cada vez que se necesita un temporal . Sin embargo, los nombres temporales utilizados para guardar valores intermedios de los clculos de expresiones tienen que ser introa ducidos en la tabla de s mbolos para guardar sus valores con el consiguiente aumento de espacio. Los nombres temporales se pueden reutilizar mediante un sencillo mtodo que consiste en llevar una cuenta c, iniciada a cero, de e variables temporales. Cuando se utilice un nombre temporal como operando hay que decrementar el valor de c en 1. Siempre que se genere un nuevo nombre temporal se usa el valor del contador (sprintf(simbolo,t %d,c)) y se incrementa el valor de c en 1. Consideremos el ejemplo: x = a b + c d e f
= id (x) * a b c + * d e * f

Figura 7.4: Arbol sintctico para el ejemplo x=a*b+c*d-e*f a

7.3. CODIGO INTERMEDIO COMO UN ATRIBUTO SINTETIZADO 227 Proposicin o t0 = a * b t1 = c * d t0 = t0 + t1 t1 = e * f t0 = t0 - t1 x = t0 Valor de c 0 1 2 1 2 1 0

Cuidado: este mtodo no es aplicable para temporales que se e utilizan ms de una vez. Por ejemplo, al evaluar una expresin en a o una proposicin condicional. A estos valores hay que asignarles o nombres temporales creados con un nombre propio.

228CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.4.

Traduccin de proposiciones de asignacin o o y expresiones aritmticas e

La tabla 7.4 a continuacin muestra como se puede realizar la o traduccin de expresiones aritmticas ms complejas. La funcin o e a o gen cuad(op, result, arg1, arg2) genera el correspondiente cdigo de 3-direcciones en notacin o o de cudruplos. Cada vez que es llamada genera una lista de cdigo a o con slo un cudruplo. o a
Produccin o S id := E E E1 + E2 E E1 E2 E E1 E (E1 ) E id Reglas Semnticas a S.cod = E.cod//gen cuad(ASSIGN, id.lugar, E.lugar, ) E.lugar = nuevotemp() E.cod = E1 .cod//E2 .cod//gen cuad(ADD, E.lugar, E1 .lugar, E2 .lugar) E.lugar = nuevotemp() E.cod = E1 .cod//E2 .cod//gen cuad(M U LT, E.lugar, E1 .lugar, E2 .lugar) E.lugar = nuevotemp() E.cod = E1 .cod//gen cuad(U M IN U S, E.lugar, E1 .lugar, ) E.lugar = E1 .lugar E.cod = E1 .cod E.lugar = lexema(id) E.cod = Cuadro 7.4: ETDS para expresiones aritmticas e

En la prctica las proposiciones de 3-direcciones se pueden escribir a de forma consecutiva a un archivo de salida en lugar de construir la lista de proposiciones en el atributo cod, lo que facilita la implementacin. o Veamos ahora como se puede implantar una funcin recursiva que o genera el cdigo de 3-direcciones, que llamaremos genera cdigo(). o o Al n y al cabo se trata de un atributo sintetizado y podemos recorrer el rbol en modo postjo. Supongamos que la funcin a o devuelve un registro llamado TAC (Three-Address-Code), que contiene dos campos: lugar (nombre temporal donde se almacena el valor de una

7.4. TRADUCCION DE PROPOSICIONES DE ASIGNACION Y EXPRESIONES ARITMETICAS2

expresin) o cod (puntero a la lista de cudruplos que almacena el cdia o go). Se utiliza el lexema, pero ser en realidad un puntero a la tabla a de s mbolos.

230CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION


typedef enum {n assign, n mult, n add, n id, ...} NodeKind; typedef struct streenode { NodeKind kind; int nchilds; // nmero de hijos u struct streenode childs[MAXNUMCHILDS]; // se puede usar una lista con primer hijo que apunta a hermanos int val; // para constantes numricas e char *strval; // para identificadores, deberia ser puntero a la TS } STreeNode; typedef STreeNode * SyntaxTreeRoot; typedef struct { char lugar[10]; lista codigo *cod; //puntero a lista de cudruplos a } TAC;

= E

n_mas

n_menos

n_mult

n_uminus

id

E1

E2

E1

E2

E1

E2

n_id

n_num

Figura 7.5: Tipos de nodo


TAC genera cdigo (STreeNode *nodo) { o TAC datos; TAC aux1, aux2; lista codigo *cod=NULL; datos.cod=NULL; switch (node->kind) { case n assign: // childs[0]=id, childs[1]=E aux1=genera codigo(childs[1]); cod=gen cuad(assign, lexema(id), aux1.lugar,--); datos.cod=concatena codigo(aux1.cod,cod); break; case n add: // childs[0]=E1 , childs[1]=E2 aux1=genera codigo(childs[0]);

7.4. TRADUCCION DE PROPOSICIONES DE ASIGNACION Y EXPRESIONES ARITMETICAS2


aux2=genera codigo(childs[1]); datos.lugar=nuevotemp(); cod=gen cuad(add, datos.lugar,aux1.lugar,aux2.lugar); datos.cod=concatena codigo(aux1.cod,aux2.cod,cod); break; case n mult: // childs[0]=E1 , childs[1]=E2 aux1=genera codigo(childs[0]); aux2=genera codigo(childs[1]); datos.lugar=nuevotemp(); cod=gen cuad(mult, datos.lugar,aux1.lugar,aux2.lugar); datos.cod=concatena codigo(aux1.cod,aux2.cod,cod); break; case n parentesis: // childs[1]=E // no haria falta crear este tipo de nodo datos=genera codigo(childs[1]); break; case n id: datos.lugar=lexema(id); datos.cod=NULL; break; } case n num: datos.lugar=lexema(num); datos.cod=NULL; break; } return(datos); }

232CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.5.

Traduccin de expresiones booleanas o

Las expresiones booleanas se utilizan principalmente como parte de las proposiciones condicionales que alteran el ujo de control del programa, if-then, if-then-else, while-do. Las expresiones booleanas se componen de los operadores booleanos and,or,not aplicados a variables booleanas o expresiones relacionales. A su vez, las expresiones relacionales son de la forma E1 oprel E2 , donde E1 y E2 son expresiones aritmticas y oprel es cualquier e operador relacional <, >, <=, >=,.... Consideremos expresiones booleanas generadas por la gramtica: a
E E or E | E and E | not E | ( E ) | id oprel id | true | false | id

Uno de los mtodos para traducir expresiones booleanas a cdigo e o de 3-direcciones consiste en codicar numricamente los valores e true y false y evaluar una expresin booleana como una expreo sin aritmtica, siguiendo unas prioridades. A menudo se utiliza o e 1 para indicar true y 0 para indicar false. Las expresiones booleanas se evalan de manera similar a una exu presin aritmtica de izquierda a derecha. Supongamos el ejempo e lo: a or b and not c. La secuencia de cdigo de 3-direcciones o correspondiente es: t1 = a or b t2 = not c t3 = t1 and t2 La siguiente gramtica en la tabla 7.5 muestra el ETDS para a producir cdigo de 3-direcciones para las expresiones booleanas. o La funcin para generar cdigo se podr ampliar aadiendo nuevos o o a n casos a la sentencia switch correspondientes a los tipos de no-

7.5. TRADUCCION DE EXPRESIONES BOOLEANAS Produccin o E E1 or E2 E E1 and E2 E not E1 E (E1 ) E id1 oprel id1 E true E f alse E id Reglas Semnticas a E.lugar = nuevotemp()

233

E.cod = E1 .cod//E2 .cod//gen cuad(or, E.lugar, E1 .lugar, E2 .lugar) E.lugar = nuevotemp() E.cod = E1 .cod//E2 .cod//gen cuad(and, E.lugar, E1 .lugar, E2 .lugar) E.lugar = nuevotemp() E.cod = E1 .cod//gen cuad(not, E.lugar, E1 .lugar, ) E.lugar = E1 .lugar E.cod = E1 .cod E.lugar = nuevotemp(); E.cod = gen cuad(oprel, E.lugar, lexema(id1 ), lexema(id2 )) E.lugar = nuevotemp(); E.cod = gen cuad(assign, E.lugar, 1, ) E.lugar = nuevotemp(); E.cod = gen cuad(assign, E.lugar, 0, ) E.lugar = lexema(id) E.cod = Cuadro 7.5: ETDS para expresiones booleanas utilizando una representacin o numrica e

dos asociados a los operadores lgicos. Por ejemplo, para el nodo o correspondiente al operador lgico and, nodo tipo n and, se ino sertar el siguiente trozo de cdigo: a o case n and: // childs[0]=E1 , childs[1]=E2 aux1=genera codigo(childs[0]); aux2=genera codigo(childs[1]); datos.lugar=nuevotemp(); cod=gen cuad(and, datos.lugar,aux1.lugar,aux2.lugar); datos.cod=concatena codigo(aux1.cod,aux2.cod,cod); break;

234CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.6.

Traduccin de proposiciones de control o

Pasemos a considerar ahora la traduccin de proposiciones de cono trol if-then, if-then-else, while-do generadas por la siguiente gramtica: a
S if E then S1 | if E then S1 else S2 | while E do S1

7.6.1.

Proposicin if-then o

Supongamos una sentencia if-then de la forma S if E then S1 , ver diagrama de ujo en gura 7.6. Para generar el cdigo correspondiente a esta proposicin habr que aadir a o o a n la funcin genera cdigo() un nuevo caso para la sentencia o o switch que contemple este tipo de nodo en el rbol sintctico, a a nodo n ifthen.
CODIGO CALCULO E

SALTO CONDICIONAL V CODIGO S Etiqueta 1

n_ifthen

(a)

(b)

Figura 7.6: (a) Diagrama de ujo para la proposicin if-then y (b) tipo de o nodo
TAC datos; TAC aux1, aux2; lista codigo *cod; datos.cod=NULL; direcciones dir; //usamos direccin al salto, en vez de etiquetas o case n ifthen: // childs[0]=E, childs[1]=S1 aux1=genera codigo(childs[0]); cod=gen cuad(if false,--, aux1.lugar, dir?); // an no se sabe la direc. de salto u aux2=genera codigo(childs[1]);

7.6. TRADUCCION DE PROPOSICIONES DE CONTROL


dir=sgtedirlibre(); //relleno de retroceso rellena(cod,arg3,dir)

235

datos.cod=concatena codigo(aux1.cod,cod,aux2.cod); break;

Supondremos que tenemos una funcin, sigtedirlibre(), que o guarda el ndice de la siguiente instruccin libre (la funcin gen cuad() o o incrementa ese contador). En la implantacin se ha optado por o utilizar direcciones directamente a las instrucciones en vez de usar etiquetas. 7.6.2. Proposicin if-then-else o

Supongamos una sentencia if-then-else de la forma S if E then S1 else S2 , cuyo diagrama de ujo tiene la forma representada en la gura 7.7. Para generar el cdigo correspondio ente a esta proposicin habr que aadir a la funcin genera cdigo() o a n o o un nuevo caso para la sentencia switch que contemple este tipo de nodo en el rbol sintctico, nodo n ifthenelse. Este fraga a mento de cdigo se podr implantar de forma similar a como o a hemos hecho en la seccin anterior. Ver ejercicios. o

CODIGO CALCULO E

SALTO CONDICIONAL V CODIGO S1

SALTO INCONDICIONAL Etiqueta 2 CODIGO S2 Etiqueta 1

n_ifthen_else

S1

S2

(a=

(b)

Figura 7.7: (a)Diagrama de ujo para la proposicin if-then-else y (b) tipo o de nodo

236CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.6.3.

Proposicin while-do o

Una sentencia while -do tiene la forma S while E do S1 , cuyo diagrama de ujo viene representado en la gura 7.8. Para generar el cdigo correspondiente a esta proposicin habr o o a que aadir a la funcin genera cdigo() un nuevo caso para n o o la sentencia switch que contemple este tipo de nodo en el rbol a sintctico. a
Etiqueta 1 CODIGO CALCULO E

SALTO CONDICIONAL V CODIGO S

n_while
SALTO INCONDICIONAL Etiqueta 2

(a=

(b)

Figura 7.8: (a)Diagrama de ujo para la proposicin while do y (b) tipo de o nodo

Supondremos que tenemos una funcin, sigtedirlibre(), que guaro da el ndice de la siguiente instruccin libre (se asume que la o funcin gen cuad() incrementa ese contador). o
TAC datos; datos.cod=NULL; TAC aux1, aux2; lista codigo *cod1=NULL, *cod2=NULL; direcciones dir1,dir2; case n while: // childs[0]=E, childs[1]=S1 dir1=sgtedirlibre(); aux1=genera codigo(childs[0]); cod1=gen cuad(if false,--, aux1.lugar, dir?); aux2=genera codigo(childs[1]); cod2=gen cuad(goto,--, dir1,--);// salto incondicional a dir1 dir2=sigtedirlibre(); // rellena argumento de cod1, direccion salto condicional

7.6. TRADUCCION DE PROPOSICIONES DE CONTROL


rellena(cod1,arg3,dir2)

237

datos.cod=concatena codigo(aux1.cod,cod1,aux2.cod,cod2); break;

Se ha optado por utilizar direcciones directamente a las instrucciones en vez de etiquetas.

238CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.7.

Traduccin de funciones o

En esta seccin se describe en trminos generales el mecanismo o e de generacin de cdigo de 3-direcciones para funciones. La geno o eracin de cdigo para las funciones es la parte ms complicada o o a porque depende de la mquina objeto y de la organizacin del a o entorno de ejecucin. La traduccin de funciones implica dos etao o pas: la denicin de la funcin. Una denicin de funcin crea o o o o un nombre, parmetros y cdigo del cuerpo de la funcin pero a o o no se ejecuta la funcin en ese punto. o la llamada a la funcin desde una parte del programa o (trataremos a los procedimientos como funciones que no devuelven valores). Una llamada crea los valores actuales para los parmetros y realiza un salto al cdigo de entrada de la a o funcin que se ejecuta y retorna al punto de la llamada. o Supongamos que el subrbol sintctico correspondiente a una funa a cin tiene como ra un nodo de tipo n call, llamada a funcin, o z o con una serie de hijos que corresponden a los argumentos, que en general, sern expresiones E1 , . . . , En a evaluar para obtener el a valor actual de los n-argumentos.

A continuacin se incluye una implantacin para generar el cdio o o go de 3-direcciones correspondiente a la llamada de la funcin en o primer lugar. Posteriormente analizaremos el caso de la denicin o de la funcin. Supondremos que se han comprobado previamente o las condiciones semnticas de la llamada (nmero y tipo de argua u mentos).
Ejemplo de llamada a la funcin o

La llamada a una funcin de dos argumentos genera el siguiente o cdigo intermedio: o Se hace uso de una pila en donde se apilan los valores actuales de los parmetros de la funcin para despus, como veremos en el a o e

7.7. TRADUCCION DE FUNCIONES

239

Calculo de los param. de F

Apilar direccion de retorno de F Punto de entrada a F Desapilar valores parametros Llamada CALL/ Salto a F . . Cuerpo de F : Apilar valor de retorno Recoger valor de retorno Salto retorno

Apilar argumentos (paso de parametros)

Figura 7.9: Diagrama de ujo para la llamada a funcin o ASIGN C PUSH PUSH PUSH CALL POP t0 t0 t1 t2 X t3 147 // asigna la direccin de retorno 147 a t0 (la siguiente al CALL) o // apila la direccin de retorno o // apila el valor de t1, primer arg. de la funcin o // apila el valor de t2, segundo arg. de la funcin o // salta a la direccin X, entrada a la funcin o o // direccion 147, se desapila el valor devuelto por la funcin, se almacena en t3 o Cuadro 7.6: Ejemplo de cdigo de llamada a una funcin o o

siguiente apartado, en la implantacin del cuerpo de la funcin, o o desapilarlos.

Nota: Respecto a la direccin de la llamada a la funcin ( o o ndice de la instruccin del cdigo de entrada a la funcin), se podr o o o a conocer en el caso de que el cdigo para la funcin ya se hubiera o o generado antes de la llamada (por ejemplo, se podr haber ala macenado en la entrada de la tabla de s mbolos correspondiente a esa funcin en un campo denido para ese propsito). o o

240CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

En el caso de que an no se haya generado el cdigo para la deniu o cin de la funcin tendr o o amos que hacer un relleno de retroceso en todas las llamadas a esa funcin. Una forma ser para cada funo a cin almacenar los o ndices de las instrucciones donde se hace una llamada a dicha funcin (por ejemplo, en un vector de o ndices) y una vez denida la funcin que ya se conoce la direccin de entrao o da recorremos el vector de ndices y rellenamos con la direccin o adecuada en todas las proposiciones de llamadas a esa funcin. o

7.7. TRADUCCION DE FUNCIONES TAC datos; datos.cod=NULL; TAC aux[MAXNCHILDS]; cuadruplos cod1, cod2, codpush[MAXNCHILDS], codcall, codpop; direcciones dir1,dir2; //direcciones a los saltos char *t0, *t1; // varibales temporales

241

case n call: // clculo de los parmetros de la funcin a a o for(i = 0; i<nchilds;i++) aux[i] = genera cdigo(childs[i]); o t0 = nuevotemp(); //asigna en t0 la direc. de retorno de la func., an no se sabe u cod1 = gen cuad(ASSIGN,t0,dir1?); cod2 = gen cuad(PUSH,,t0,); // apilamos la direc. de retorno // apilamos los argumentos for(i = 0; i<nchilds;i++) codpush[i] = gen cuad(PUSH,, aux[i].lugar,)); // llamada a la func., no se sabe an la direcc. de su cuerpo u codcall = gen cuad(CALL, , dir2?,); // la siguiente direccin libre es la de retorno o dir1 = sigtedirlibre(); rellena(cod1,arg3,dir1); t1 = nuevotemp(); // recogemos el valor devuelto por la funcion codpop = gen cuad(POP,t1,,) ; datos.cod=concatena(losaux[i].cod,cod1,cod2,loscodpush[i],codcall,codpop); datos.lugar = t1; //para relleno de retroceso de dir2, vease Nota return (datos);

Figura 7.10: Implantacin de la llamada a funciones o

242CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Cuerpo de la funcin o Para traducir el cuerpo de la funcin bastar recorrer el rbol o a a hasta encontrar un nodo de tipo n function a partir del cual colgar el bloque de sentencias del cuerpo de la funcin. No har a o a falta generar la parte del rbol de los argumentos ya que stos a e estar almacenados en la tabla de s an mbolos. A partir de cierta direccin de cdigo intermedio deber o o amos tener un instruccin o que ser la entrada a la funcin y que contendr a o a:
POP POP ... POP t15 t10 t11 // recoge el segundo argumento // recoge el primer argumento // operaciones de la funcin que almacena el resultado en t20 (por ejemplo) o // recoge de la pila el valor de la direcc. de retorno (147) y lo pone en t15 (por ejem.)

RETURN t15 t20 // salida de la funcin: el entorno de ejecucin deber primero saltar a la instrucc. o o cuya direccin es el valor de t15 y apilar el valor devuelto que es el de t20 o

Esto implica las siguientes tareas (ver parte derecha de la gura 7.9) : 1. Recoger la direccin libre actual y utilizarla como direccin o o para rellenar (relleno con retroceso) las llamadas a la funcin o que estamos deniendo. 2. Generar cdigo para desapilar los argumentos de la funcin o o y meterlos en las variables correspondientes. 3. Generar cdigo para el bloque de sentencias S. o 4. Desapilar la direccion de retorno. 5. Generar la salida de la funcion con RETURN. 6. Unir los trozos de cdigo para tenerlos en una unica lista de o cudruplos. a

7.7. TRADUCCION DE FUNCIONES

243

TAC datos; datos.cod=NULL; TAC aux[MAXNCHILDS]; cuadruplos codpoparg[MAXNPARAM], codpopdirreturn, codreturn; direcciones dir; //direccion de retorno char *t; // varibale temporal case n function: dir = sigtedirlibre(); rellena(todas llamadas a la funcion con esta dir); // desapilamos los argumentos for(i = 0; i < nparams ;i++) codpoparg[i] = gen cuad(POP, param[i].lugar, -, -)); //genera codigo para el cuerpo de la funcin (k intrucciones) o //y calculamos el valor a devolver for(k = 0; k < nchilds; k++) aux[k] = genera cdigo(childs[k]); o t = nuevotemp(); //desapilamos la direccion de retorno de la funcin o codpopdirreturn = gen cuad(POP, t, -, -); //salida de la funcion: el entorno de ejecucin salta a la o //direcc. de retorno en t y se apila el valor devuelto codreturn = gen cuad(RETURN, t, valor devuelto, -); datos.cod=concatena(loscodpoparg[i],losaux[k].cod,codpopdirreturn,codreturn); datos.lugar = valor devuelto; return (datos); Figura 7.11: Implantacin del cuerpo de las funciones o

VUESTRA prctica 3 a En la denicin de la funcin vais a tener que colgar los o o argumentos en el rbol para saber cuantos parmetros teneis a a que desapilar cuando implementeis el cuerpo de la funcin, o pues no teneis la tabla de simbolos con esa informacin. o Para la llamada a las funciones tendre que crear a mano s un nodo n CALL, produccin FunctionStm id ( Arg ) . De o lo contrario, lo confundiria con el nodo n id. s

244CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Para colgar los parmetros en la denicin de la funcin tena o o dre que crear un nodo a mano n PARAM, produccin de s o Arg. Vamos a hacer el siguiente ejemplo. Se ha considerado que primero se genera el cdigo del programa principal y a continuacin el o o cdigo de las funciones. o
module Ejemplo ; var resultado : integer ; function Suma ( integer a, integer b) : integer ; var total: integer; begin total = a + b ; return(total) ; end Suma ; begin (* programa principal *) resultado = Suma ( 2, 4*8) ; write resultado ; end Ejemplo .

Listado de cuadruplos
00 (ASSIGN C, t1, 2, NULL) 01 (MULT, t2, 4, 8) 02 (ASSIGN C, t3, 7, NULL) 03 (PUSH, t3, NULL, NULL) 04 (PUSH, t1, NULL, NULL) 05 (PUSH, t2, NULL, NULL) 06 (CALL, 11, NULL, NULL) 07 (POP, t4, NULL, NULL) 08 (ASSIGN V, resultado, t4, NULL) 09 (WRITE, resultado, NULL, NULL) 10 (HALT, NULL, NULL, NULL) // final del programa 11 (POP, b, NULL, NULL) // entrada a la funcin o 12 (POP, a, NULL, NULL) 13 (ADD, t5, a, b) 14 (ASSIGN V, total, t5, NULL)

7.7. TRADUCCION DE FUNCIONES

245

15 (POP, t6, NULL, NULL) // desapilo la direccin de retorno, la 07 o 16 (RETURN, t6, total, NULL) // el entorno de ejecucin salta a la direccion o // en t6 (la 07) y apila el valor a devolver

246CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.8.

Optimizacin de cdigo intermedio o o

La optimizacin de cdigo intermedio se puede realizar: o o a nivel local: slo utilizan la informacin de un bloque bsico o o a para realizar la optimizacin. o a nivel global: que usan informacin de varios bloques bsicos. o a El trmino optimizacin de cdigo es inadecuado ya que no se e o o garantiza el obtener, en el sentido matemtico, el mejor cdigo a o posible atendiendo a maximizar o minimizar una funcin objetivo o (tiempo de ejecucin y espacio). El trmino de mejora de cdigo o e o ser ms apropiado que el de optimizacin. a a o Nos concentraremos bsicamente en la optimizacin de cdigo de a o o tres-direcciones, puesto que son siempre transportables a cualquier etapa nal, son optimizaciones independientes de la mquina. Las a optimizaciones a nivel de la mquina, como la asignacin de rega o istros y la utilizacin de instrucciones espec o cas de la mquina, a se salen del contexto de esta asignatura. La mayor de los programas emplean el 90 % del tiempo de ejea cucin en el 10 % de su cdigo. Lo ms adecuado es identicar las o o a partes del programa que se ejecutan ms frecuentemente y tratar a de que se ejecuten lo ms ecientemente posible. En la prctia a ca, son los lazos internos los mejores candidatos para realizar las transformaciones. Adems de la optimizacin a nivel de cdigo intermedio, se puede a o o reducir el tiempo de ejecucin de un programa actuando a otros o niveles: a nivel de cdigo fuente y a nivel de cdigo objeto. o o
Codigo fuente Etapa Inicial Codigo Intermedio Generador de Codigo Codigo Objeto
el compilador puede usar registros seleccionar instrucciones

el programador puede modificar algoritmos transformar lazos

el compilador puede mejorar los lazos

Figura 7.12: Niveles en los que el programador y el compilador pueden mejorar el cdigo o

7.8. OPTIMIZACION DE CODIGO INTERMEDIO

247

Un bloque bsico es una unidad fundamental de cdigo. Es una a o secuencia de proposiciones donde el ujo de control entra en el principio del bloque y sale al nal del bloque. Los bloques bsicos a pueden recibir el control desde ms de un punto en el programa a (se puede llegar desde varios sitios a una etiqueta) y el control puede salir desde ms de una proposicin (se podr ir a una a o a etiqueta o seguir con la siguiente instruccin). Cuando aplicamos o optimizacin dentro de un bloque bsico slo nos tenemos que o a o preocupar sobre los efectos de la optimizacin en los valores de o las variables a la entrada del bloque y los valores que tienen a la salida del bloque, que han de ser los mismos que en el cdigo o original sin transformar. El algoritmo para particionar un programa en bloques se describe a continuacin: o
1. Encontrar todas las proposiciones que comienzan el principio de un bloque bsico: a La primera sentencia del programa. Cualquier proposicin del programa que es el objetivo de un o salto. Cualquier proposicin que sigue a una bifurcacin. o o 2. Para cualquier proposicin que comienza un bloque bsico, el bloque o a consiste de esa proposicin y de todas las siguientes hasta el o principio del siguiente bloque o el final del programa.

El ujo de control de un programa puede visualizarse como un grafo dirigido de bloques bsicos. A este grafo se le llama grafo a de ujo. Como ejemplo consideremos este trozo de cdigo escrito o en pseudoC que suma los diez primeros nmeros que se muestra u en la tabla 7.7 (a):

248CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION void main() { int i,s; i=10; s=0; while i > 0 do { s=s+i; i=i-1; } } (a) (b) i = 10 s=0 label l1 t0 = i > 0 ialse t0 goto l2 s=s+i i=i-1 goto l1 label l2 ...

Cuadro 7.7: Ejemplo (a) cdigo fuente, (b) cdigo de 3-direcciones o o

La gura 7.13 muestra el diagrama de ujo para el ejemplo anterior. Aparecen 4 bloques bsicos. a
i = 10 s=0

label l1 t0 = i > 0 iffalse t0 goto l2 s= s+i i=i-1 goto l1

label l2 ...

Figura 7.13: Diagrama de ujo

7.8. OPTIMIZACION DE CODIGO INTERMEDIO

249

Algunas deniciones previas: Dada una proposicin de 3-direcciones de la forma a = b op o c decimos que la proposicin referencia b y c y que dene a. o Se dice que un nombre en un bloque bsico vive al nal del a bloque si su valor es referenciado en otro bloque bsico en el a programa. Se dice que un nombre est muerto si no es referenciado en a el resto del programa. Se presentan algunas de las transformaciones ms utiles para a mejorar el cdigo. Son transformaciones locales, se pueden realizar o observando slo las proposiciones de un bloque bsico. o a 7.8.1. Eliminacin de subexpresiones comunes o

Si una expresin se calcula ms de una vez, se puede remplazar o a el clculo de la segunda por el valor de la primera expresin. a o Consideremos el siguiente ejemplo del cdigo 7.8 (a). Vemos que o la expresin t3t1 se calcula dos veces, por tanto podemos escribir o el cdigo de la gura 7.8 (b): o
t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t3 * t1 t7 = t6 + b c = t5 * t7 (a) t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t6 + b c = t5 * t5 (b)

Cuadro 7.8: Eliminacin de subexpresiones comunes o

Esto slo es posible si los operandos que estn implicados en el o a clculo de la expresin no han modicado su valor en las proposia o ciones intermedias.

250CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.8.2.

Propagacin de copias o

La propagacin de copias considera las proposiciones de la forma o a = b. Despus de esta sentencia sabemos que a y b tienen el e mismo valor, por tanto, podemos remplazar cada vez que aparezca a por b, con la esperanza de que podamos remplazar todas las ocurrencias de a hasta que se convierta en un nombre muerto y se pueda entonces eliminar la proposicin de copia. o A partir del cdigo anterior podemos eliminar la proposicin de o o copia t6 = t4. Sustituimos t6 por t4. Vease gura 7.9 (a). Ahora se puede ver que hay de nuevo una subexpresin comn que puede o u ser eliminada, obteniendo el cdigo que se muestra en 7.9 (b). Y o nalmente realizando otra vez propagacin de copias, obtenemos o 7.9 (c):
t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t4 + b c = t5 * t7 (a) t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t5 c = t5 * t7 (b) t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b t6 = t4 t7 = t5 c = t5 * t5 (c)

Cuadro 7.9: Propagacin de copias y eliminacin de subexpresiones comunes o o

Vemos que el haber hecho una optimizacin puede dar lugar a o que sea posible aplicar nuevas optimizaciones.

7.8. OPTIMIZACION DE CODIGO INTERMEDIO

251

7.8.3.

Eliminacin de cdigo muerto o o

Podemos tener proposiciones que denen un nombre que nunca ms es referenciado, est muerto. Estas proposiciones pueden a a entonces ser eliminadas. Dada la proposicin a= b op c, se dice o que es cdigo muerto o inactivo si a no es referenciada. En genero al, el cdigo muerto aparece como consecuencia de la propagacin o o de copias y es esto lo que hace que la tcnica de propagacin de e o copias sea tan util. Veamos como aplicar esta tcnica al ejemplo e anterior en la gura 7.9 (c). Vemos que t6 y t7 no tienen ninguna referencia a partir de su denicin, por tanto pueden ser eliminadas. Obtenemos el cdigo o o que aparece en la gura 7.10. Se ha supuesto que todas las variables no-temporales estn vivas, se hace referencia a ellas en el a resto del programa.
t1 = 4 - 2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b c = t5 * t5 Cuadro 7.10: Eliminacin de cdigo muerto o o

Aunque es poco probable que el programador introduzca cdigo o muerto o inactivo, ste puede aparecer como resultado de transe formaciones anteriores.

252CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.8.4.

Transformaciones aritmticas e

Se pueden hacer uso de transformaciones algebraicas simples para reducir la cantidad de computacin transformando operao ciones ms costosas por otras menos costosas. Existen tres tipos a de transformaciones algebraicas bsicas. a Clculo previo de constantes a Se trata de calcular a nivel de compilacin el valor previo de o constantes en vez de hacerlo en tiempo de ejecucin que retaro dar la ejecucin de un programa. A esta optimizacin se le llaa o o ma clculo previo de constantes (en ingls constant folding). El a e cdigo de la gura 7.10 puede ser mejorado dando lugar al cdigo o o de la gura 7.11 (a). Haciendo una propagacin de copias y elimo inacin de cdigo muerto tenemos el cdigo de la gura 7.11 (b). o o o Realizando de nuevo un clculo previo de constantes obtenemos a 7.11 (c). Y nalmente podemos hacer de nuevo la propagacin de o copias y la eliminacin de cdigo muerto, obteniendo el cdigo de o o o la gura 7.11 (d).
t1 =2 t2 = t1 / 2 t3 = a * t2 t4 = t3 * t1 t5 = t4 + b c = t5 * t5 (a) (b) (c) (d) t2 = 2 / 2 t3 = a * t2 t4 = t3 * 2 t5 = t4 + b c = t5 * t5 t2 = 1 t3 = a * t2 t4 = t3 * 2 t5 = t4 + b c = t5 * t5 t3 = a * 1 t4 = t3 * 2 t5 = t4 + b c = t5 * t5

Cuadro 7.11: Clculo previo de constantes a

Hemos pasado de seis proposiciones a tener cuatro, eliminado una substraccin y una divisin en el proceso. o o

7.8. OPTIMIZACION DE CODIGO INTERMEDIO

253

Transformaciones algebraicas Podemos hacer uso de identidades algebraicas para simplicar el cdigo. Las principales identidades son: o x x + 0 = 0 + x = x; x 0 = x; x 1 = 1 x = x; =x 1 Partiendo de la gura 7.11 (d) podemos obtener el cdigo de o la gura 7.12 (a). De nuevo si usamos propagacin de copias y o eliminacin de cdigo muerto obtenemos el cdigo de la gura o o o 7.12 (b) :
t3 = a t4 = t3 * 2 t5 = t4 + b c = t5 * t5 (a) (b) t4 = a * 2 t5 = t4 + b c = t5 * t5

Cuadro 7.12: Identidades algebraicas

Reduccin de intensidad o En la mayor de las mquinas las operaciones de multiplicacin a a o y divisin son substancialmente ms costosas que las operaciones o a de suma y resta. Y a su vez, las potencias son ms costosas que las a multiplicaciones y divisiones. Por tanto, siempre que sea posible es conveniente sustituir un operador ms costoso por otro menos a costoso. A esto se le conoce como reduccin de la intensidad. Las o identidades ms comunes son: a x2 = x x; 2x=x+x En nuestro ejemplo de la gura 7.12 (b) podemos obtener el cdigo 7.13 o
t4 = a + a t5 = t4 + b c = t5 * t5 Cuadro 7.13: Reduccin de intensidad o

Otra transformacin t o pica es usar desplazamientos de bits cuando se divida o se multiplique por potencias de dos.

254CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

7.8.5.

Empaquetamiento de temporales

Se trata de reusar los temporales con el n de ahorrar espacio. Despus de haber optimizado el cdigo es normal pensar que e o se puedan usar menos temporales y ser conveniente entonces a renombrar estos temporales. Supongamos que tenemos una tabla de temporales disponibles (por ejemplo de t1 a t9), de manera que marcamos si un temporal est vivo en un cierto punto del bloque bsico. En general, a a es posible remplazar dos temporales por uno unico si no existe ningn punto donde los dos temporales estn vivos a la vez. Para u a cada temporal lo remplazamos por el primer temporal en la tabla que est muerto en todos los lugares en el que el temporal bajo a consideracin est vivo. o a Veamos nuestro ejemplo de la gura 7.13. t4 se dene en la primera proposicin y est vivo en la segunda, entonces lo remo a plazamos por el primer terminal muerto de la tabla, t1, obteniendo el cdigo de la gura 7.14 (a). Por otro lado, t5 es denido o en la segunda proposicin y vivo en la proposicin 3. Esto no ino o teracciona con el temporal t1, que esta vivo slo en la segunda o proposicin, por tanto t5 puede ser sustituido por t1. Obteniendo o el cdigo de la gura 7.14 (b). o
t1 = a + a t5 = t1 + b c = t5 * t5 (a) t1 = a + a t1 = t1 + b c = t1 * t1 (b)

Cuadro 7.14: Empaquetamiento de temporales

Comparando este cdigo con el original que ten ocho proposio a ciones, siete temporales, dos adiciones, una substraccin, cuatro o multiplicaciones y una divisin, lo hemos reducido a tres proposio ciones que implican dos adiciones y una multiplicacin. o 7.8.6. Mejora de los lazos

Traslado de cdigo o

7.8. OPTIMIZACION DE CODIGO INTERMEDIO

255

Una modicacin importante que disminuye la cantidad de o cdigo en un lazo es el traslado de cdigo. Esta transformacin o o o toma una expresin que produce el mismo resultado independio entemente del nmero de veces que se ejecute un lazo y la coloca u antes del lazo. Por ejemplo:
while (i<=limite-2) ...

Se puede transformar en:


t=limite -2; while (i<=t) ...

256CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Variables de induccin o Se trata de identicar las variables que permanecen ligadas entre s en la ejecucin, estn relacionadas entre s de forma que o a conocido el valor de una se puede obtener el de la otra. Supongamos el siguiente fragmento de cdigo donde se ha supuesto que o los elementos de la matriz ocupan 4 bytes y ya se ha realizado cierta optimacin. o
suma=0; j=0; while j<10 { suma = suma + a[j]; j=j+1; } ... suma=0; j=0; label l1 t1= j<10 ialse t1 goto l2 t2=4*j t3=a[t2] suma=suma+t3 j=j+1 goto l1 label l2 ... Cuadro 7.15: (a) cdigo fuente y (b) cdigo de 3-direcciones o o

donde a[t2] en la tabla 7.15 (b) signica la direccin de a ms un o a desplazamiento t2. Sabemos que t2 no cambia en ningn momento u salvo en t2 = 4 j, por tanto justo despus de la proposicin e o j = j + 1 se cumple que t2 = 4 j + 4, y se puede sustituir la asignacin t2 = 4 j por t2 = t2 + 4, debiendo inicializar el valor o de t2 = 0. Siempre que haya variables de induccin se pueden hacer sustituo ciones de este tipo y eliminar todas menos una.

7.9. EJERCICIOS

257

7.9.

Ejercicios

1. (0.25 ptos) Escribe el pseudocdigo correspondiente, usando o la notacin que hemos visto a lo largo del cap o tulo, para la implementacin de la generacin de cdigo de tres direcciones o o o medinate cuadrplos para la construccion if-then-else. u 2. (0.25 ptos) Escribe el pseudocdigo correspondiente, usando o la notacin que hemos visto a lo largo del cap o tulo, para la implementacin de la generacin de cdigo de tres direcciones o o o medinate cuadrplos para la construccin repeat until. u o 3. (0.25 ptos) Escribe el pseudocdigo correspondiente, usando o la notacin que hemos visto a lo largo del cap o tulo, para la implementacin de la generacin de cdigo de tres direcciones o o o medinate cuadrplos para la construccin switch. u o o 4. (0.3 ptos) Supongamos una nueva construccin de los lenguajes de programacin que llamaremos do-while-do (hacero mientras-hacer). Esta construccin nace de forma natural, o como las construcciones while-do, do-while que ya conocis. e Esta construccin surge para implementar la idea en que hay o casos en los que no se desea salir de la iteracin al principio, o ni al nal de la iteracin, sino a la mitad, despus de que se o e ha hecho cierto procesamiento. Por ejemplo para implementar el cdigo: o
dowhiledo read(X); while (no final fichero) process(X); end dowhiledo

La sintaxis de esta construccin es: o S dowhiledo S while E S end dowhiledo | donde se ha usado el operador * para indicar cero o ms a repeticiones. Se pide:

258CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Dibujar el diagrama de ujo de esta construccin. o Dibujar la forma del rbol abstracto de anlisis sintctia a a co que usar para su traduccin a cdigo de 3-direcciones. as o o Escribir el pseudocdigo de la funcin generar cdigo para o o o traducir este tipo de sentencias a una lista de cudruplos. a Desafortunadamente ningn lenguaje comn de prograu u macin implementa esta construccin. A qu crees que o o e se debe esto?. Qu construccin(es) usa el lenguaje C e o para implementar esta idea?

7.10. EJEMPLO DE GENERACION DE CODIGO PARA UNA CALCULADORA USANDO PCCTS

7.10.

Ejemplo de generacin de cdigo para o o una calculadora usando PCCTS

Supongamos una pequea calculadora que realizar operaciones n aritmticas sencillas segn la gramtica: e u a
entrada ecuacion expresion termino factor dato (ecuacion)+ id = expresion ; termino ( + termino | - termino )* factor ( * factor | / factor)* ( expresion ) | dato num | id | - num | - id

Se pide implementar un traductor que traduzca las expresiones aritmticas a cdigo de 3-direcciones, implementado medie o ante cuduplos de la forma (operador, resultado, arg1, a arg2). Los tipos de operadores son:
(ASSIGN, result, arg1,NULL) (ADD, result, arg1,arg2) (SUB, result, arg1,arg2) (MULT, result, arg1,arg2) (DIV, result, arg1,arg2) (NEG, result, arg1,NULL) (HALT,NULL, NULL, NULL) asigna arg1 a result suma arg1, arg2 y lo alamacena en result resta arg1, arg2 y lo alamacena en result multiplica arg1, arg2 y lo alamacena en result divide arg1, argg2 y lo alamacena en result mult. por (-1) arg1, y lo alamacena en result nal de programa

260CAP ITULO 7. GENERACION DE CODIGO INTERMEDIO. OPTIMIZACION

Se ha implementado la clase cuadruplo (Cuad.h). Se ha implementado la clase TAC (Three-Address-Code), a partir de una lista de cuaduplos y se ha introducido el lugar como un dato protegido adicional. Se ha implementado el mtodo generar cdigo en la e o clase AST. Fichero con la especicacion de la gramtica p3.g. a Para la entrada: a=3+2; b=a*2; c=a+b+2*6; d=-1+a; Obtenemos la salida: ( ENTRADA ( = a ( + 3 2 ) ) ( = b ( * a 2 ) ) ( = c ( + ( + a b ) ( * 2 6 ) ) ) ( = d ( + ( UMINUS 1 ) a ) ) ) Numero de lineas analizadas 6 (ADD,t0,3,2) (ASSIGN,a,t0,NULL) (MULT,t1,a,2) (ASSIGN,b,t1,NULL) (ADD,t2,a,b) (MULT,t3,2,6) (ADD,t4,t2,t3) (ASSIGN,c,t4,NULL) (NEG,t5,1,NULL) (ADD,t6,t5,a) (ASSIGN,d,t6,NULL) (HALT,NULL,NULL,NULL) Numero de cuadruplos 12

Vous aimerez peut-être aussi