Compiladores II
Optimizacin
Se realiza despus de la generacin de cdigo de todo el programa o de un elemento ejecutable del programa (funcin, procedimiento, etc). Dependiente del contexto
Compiladores II
Compiladores II
Optimizacin Objetivo
Obtener cdigo que se ejecuta ms eficientemente segn los criterios
Tiempo de ejecucin (optimizacin temporal) Espacio de memoria utilizado (optimizacin espacial)
Funcionamiento
Revisa el cdigo generado a varios niveles de abstraccin y realiza las optimizaciones aplicables al nivel de abstraccin
Representaciones de cdigo intermedio de ms a menos abstractas
rbol sintctico abstracto: optimizar subexpresiones redundantes, reduccin de frecuencia, etc. Tuplas o cuadruplas: optimizar en uso de los registros o de las variables temporales. Ensamblador/Cdigo mquina: convertir saltos a saltos cortos, reordenar instrucciones
Compiladores II 4
Pasar a
A=c*d; B=A*3;
Compiladores II 5
Optimizacin Local Las optimizaciones locales se realizan sobre el bloque bsico Optimizaciones locales
Folding Propagacin de constantes Reduccin de potencia Reduccin de subexpresiones comunes
Compiladores II
Bloque Bsico Un bloque bsico es un fragmento de cdigo que tiene una nica entrada y salida, y cuyas instrucciones se ejecutan secuencialmente. Implicaciones:
Si se ejecuta una instruccin del bloque se ejecutan todas en un orden conocido en tiempo de compilacin.
La idea del bloque bsico es encontrar partes del programa cuyo anlisis necesario para la optimizacin sea lo ms simple posible.
Compiladores II
Compiladores II
Separacin correcta
for (i=1;i<10;++i) { b=b+a[i]; c=b*i; } a=3; b=4; goto l1; c=10; l1: d=3; e=4;
BB1: i=1; BB2: i<10; BB3: b=b+a[i]; c=b*i; ++i BB4: a=3; b=4; goto l1; BB5: c=10; BB6: l1: d=3; e=4;
Compiladores II
Ensamblamiento (Folding) El ensamblamiento es remplazar las expresiones por su resultado cuando se pueden evaluar en tiempo de compilacin (resultado constante).
Ejemplo: A=2+3+A+C -> A=5+A+C
Estas optimizaciones permiten que el programador utilice clculos entre constantes representados explcitamente sin introducir ineficiencias.
Compiladores II
10
Implementacin del Folding Implementacin del floding durante la generacin de cdigo realizada conjuntamente con el anlisis sintctico
Se aade el atributo de constante temporal a los smbolos no terminales y a las variables de la tabla de smbolos. Se aade el procesamiento de las constantes a las reglas de anlisis de expresiones. Optimiza: 2+3+b -> 5+b
Hay una suma de constantes (2+3)+b
Compiladores II
11
Compiladores II
12
+- 3 +- + +- 5 +- 6 * +- A +- 10
Resultado: -4-(A*10)
Compiladores II 13
Propagacin de constantes Desde que se asigna a una variable un valor constante hasta la siguiente asignacin, se considera a la variable equivalente a la constante. Ejemplo: Propagacin Ensamblamiento
PI=3.14 -> PI=3.14 -> PI=3.14 G2R=PI/180 -> G2R=3.14/180 -> G2R=0.017
Estas optimizaciones permiten que el programador utilice variables como constantes sin introducir ineficiencias. Por ejemplo en C no hay constantes y ser lo mismo utilizar
Int a=10; #define a 10
Con la ventaja que la variable puede ser local. Actualmente en C se puede definir const int a=10;
Compiladores II 14
Para asignaciones
Eliminar del conjunto de definiciones la definicin de la variable asignada Aadir la definicin de la variable asignada si se le asigna una constante
Compiladores II 15
i=0; b=5;
Fun f(x,y)=> { i=0; b=5; while (i<x) { print(i*b); i=i+1; } x*b } i<x
i b
print(i*b); i=i+1;
i 1
X*b
Cada bloque bsico es una lista de apuntadores a las expresiones o asignaciones del rbol
16
Compiladores II
Ejemplo Cdigo a=10; b=c*a; a=b+a; Resultado a=10; {(a,10)} b=c*10; {(a,10)} a=b+10; {} Conjunto de definiciones {}
Compiladores II
17
Ejemplo
a[i]=10; b=a[i]+a[j]; a[j]=20; b=a[i]+a[j]; a[i]=10; b=10+a[j]; a[j]=20; b=a[i]+20; {} {(a[i],10)} {(a[i],10)} {(a[j],20)} {(a[j],20)} {(a[j],20)}
18
Compiladores II
Extensin de la P.C. Fuera del Bloque Bsico Extender la aplicacin fuera del bloque bsico
Hay que realizar un anlisis del flujo de ejecucin y es complejo. Ejemplo:
i=0; loop: i=i+1 if (i<10) goto loop; Se transforma errneamente en i=0; loop: i=1 if (1<10) goto loop;
Compiladores II
19
Reduccin de potencia(strength reduction) Se busca sustituir operaciones costosas por otras mas simples. Ejemplo:
sustituir productos por sumas.
a=2*a a=a+a
Compiladores II
20
Implementacin de la Reduccin de Potencia Buscar subrboles que se puedan sustituir por otros menos costosos. Estas sustituciones se representan como reglas que aplicar la reduccin de potencia
Exp*1 -> Exp 1*Exp -> Exp Exp+0 -> Exp 0+Exp -> Exp Exp*cte(110) -> (Exp << 2)+(Exp << 1) Exp*0 -> { llamar a las funciones de Exp } ;0 Etc.
Compiladores II
21
Compiladores II
22
Implementacin
Primero se aplica el folding y la propagacin de constantes (simplificar las expresiones) Despus se reordena el rbol sintctico hasta obtener la forma normal. Se inicia la eliminacin de las subexpresiones redundantes. Hay que considerar las asignaciones que pueden convertir una subexpresion redundante en no redundante. Ejemplo: Q=A+B A=Q^2+2 A+B no es redundante por la C[1]=A+B+P asignacin Sustituir todas las variables asignadas por la expresin que se les ha asignado Generar un orden de ejecucin Sustituir siguiendo este orden de ejecucin
Compiladores II
23
Implementacin Comparar los subrboles desde las ramas hacia la raz y sustituir los subrboles repetidos. Recorrer el grafo acclico generado y sustituir la primera aparicin de cada rama que sea hijo de dos o ms nodos por una asignacin a una variable local y las otras ramas por la variable local.
Compiladores II
24
Optimizaciones Dentro de Bucles La optimizacin de bucles es muy importante por las mejoras en tiempo de ejecucin que se obtienen Estrategias de optimizacin dentro de bucles
Expansin de bucles (loop unrolling) Reduccin de frecuencia (frequency reduction) Reduccin de potencia (strength reduction)
Compiladores II
25
Expansin de bucles(loop unrolling) La expansin de bucles solo se puede aplicar a los bucles cuyo nmero de iteraciones se conoce en tiempo de compilacin. Ejemplo:
Se puede aplicar a los bucles
for i=1 to 10 do
La expansin de un bucle puede ser muy costosa en espacio. Hay que poner un criterio heurstico para decidir si se aplica la expansin.
Se puede aplicar una expansin parcial en la que sigue existiendo el bucle, pero cada iteracin del nuevo bucle corresponde a varias iteraciones del bucle original.
En un bucle expandido se ha de sustituir el ndice del bucle por el valor constante correspondiente
Compiladores II 26
Reduccin de frecuencia. (frequency reduction) La reduccin de frecuencia detecta las operaciones invariantes de bucle y las calcula una nica vez delante del bucle. Ejemplo:
for i=1 to n do c=i*sin(a); sin(a) es una operacin invariante del bucle que puede pasar de calcularse n veces a una con la siguiente transformacin tmp=sin(a); for i=1 to n do c=i*tmp; Esta transformacin no tiene en cuenta que el bucle igual no se ejecuta ninguna vez y esto supondra perder tiempo de ejecucin calculando la invariante de bucle innecesariamente. Adems el calculo de la invariante puede producir un error de ejecucin. Por ejemplo una divisin por cero.
Compiladores II 27
Reduccin de frecuencia. (frequency reduction) Las invariantes de bucle slo pueden estar formadas por operaciones que son funciones puras
Su nico efecto es el clculo del resultado El resultado solo depende de los operandos.
Ejemplo:
Invariantes: +. -, *, / , sin, ln No invariantes: printf, getchar, ++, random
Consideracin prctica
Slo pueden ser invariantes operaciones primitivas del lenguaje (son aquellas que implementa directamente el compilador). Ejemplo: operaciones aritmticas, comparaciones, etc. Algunos compiladores permiten indicar que una funcin es pura para que pueda formar parte de invariantes
Compiladores II 28
Asociar a cada expresin invariante una variable temporal. Sustituir en el bucle las operaciones invariantes por las correspondientes variables. Aadir delante del bucle la asignacin de la expresin invariante a su variable temporal.
do instruccin while (cond); clculo de invariantes; do instruccin while (cond); for (inicializacin; condicin; incremento) instruccin inicializacin; if (cond) { clculo de invariantes; do instruccin; incremento; while (cond); }
Compiladores II 30
Problemas a resolver
Detectar las invariantes de bucle
Ya esta solucionado
Compiladores II
31
Variables Inductivas Una variable V es inductiva cuando la nica forma en que se modifica su cdigo es V=V+K, donde K es una invariante de bucle. Se considerar la necesidad de generar una variable inductiva temporal T a partir de encontrar expresiones de la forma V*C, donde C es una invariante de bucle.
Se sustituir V*C por T Se inicializa T despus de la inicializacin de V como T=V*C (solo se ejecuta al entrar en el bucle) Al final de cada iteracin se aade T=T+C*K
Compiladores II
32
Optimizacin Global
Grafo del flujo de ejecucin Antes de realizar una optimizacin global es necesario crear el grafo de flujo de ejecucin. El grafo de flujo de ejecucin representa todos los caminos posibles de ejecucin del programa. La informacin contenida en el grafo es til para
el programador y el optimizador
La optimizacin global a partir del anlisis del grafo del flujo de ejecucin permite Una propagacin de constantes fuera del bloque bsico. Eliminacin del cdigo no utilizado Una mejor asignacin de los registros. Etc. Problema: la optimizacin global es muy costosa en tiempo de compilacin
33
Compiladores II
Tipos de grafo
Orientado a procedimiento/funcin Grafo de llamadas
Ejemplo
int fact(int n) { int r; r=1; i=1; while (i<=n) { r=r*i; ++i; } return r; }
Compiladores II
r=1 i=1
bloque bsico
r=r*i; ++i;
while (i<=n)
bloque bsico
return r;
34
En el grafo, los vrtices representan los bloques bsicos y las aristas representan los saltos de un bloque bsico a otro.
Compiladores II
35
Deteccin de Cdigo no Utilizado (Cdigo Muerto) Cdigo muerto: es cdigo que nunca se ejecutar. Deteccin de cdigo no utilizado
El cdigo no utilizado son los bloques bsicos donde no llega ninguna arista. Se quita el bloque y las aristas que salen de l. Repetir hasta no eliminar ningn bloque bsico.
Compiladores II
36
Anlisis del Grafo del Flujo de Ejecucin Hay que considerar como la informacin sobre las variables y expresiones se propaga a travs del grafo. Esta informacin la representaremos en forma de conjuntos como los siguientes:
expresiones disponibles Alcance de las definiciones variables vivas expresiones muy utilizadas
Compiladores II
37
Anlisis del Grafo del Flujo de Ejecucin Los conjuntos se calculan para los puntos del grafo de flujo de ejecucin. Un punto es una posicin dentro del grafo y se encuentra entre instrucciones o bloques bsicos.
r=1 i=1
Puntos
while (i<=n)
Compiladores II
38
Expresiones Disponibles (Available expresions) El problema de las expresiones disponibles consiste en determinar que expresiones estn disponibles al inicio de cada bloque bsico. Una expresin esta disponible en un punto si el resultado que se obtuvo cuando se calculo an es el mismo que si se vuelve a calcular en el punto en que estamos. Ejemplo:
k=b+c; r=d*e b=5; En este punto d*e es una expresin disponible y b+c no lo es porque se ha modificado b.
Compiladores II
39
Compiladores II
40
Compiladores II
41
Alcance de las Definiciones (reaching definitions) El valor de una variable se define cuando se le asigna un valor. Este valor definido se pierde cuando se realiza una nueva asignacin. El problema del alcance de las definiciones es el mismo que el problema de las expresiones disponibles, pero en el caso de las variables. Ecuaciones:
RD_BOT(BB)=(RD_TOP(BB)-RD_KILL(BB)) RD_GEN(BB) RD_TOP(BB)= p precedente de BB RD_BOT(P)
Compiladores II
42
Alcance de las Definiciones (reaching definitions) Usos del alcance de las definiciones
Reutilizacin de copias en registros
Asignamos un valor a una variable. Este se encuentra en un registro del procesador. Si ms adelante necesitamos el valor de la variable podemos evitar acceder a memoria y reutilizar el valor que hay en el registro si pertenece al conjunto de las definiciones.
Propagacin de constantes
Hay que ver que una variable est definida con una constante y se podr sustituir por esta cuanto se quiera leer
Compiladores II
43
Variables Vivas (live variables) Una variable esta viva en un punto p cuando su valor es requerido ms adelante en un un camino de ejecucin que pasa por p. Un camino requiere el valor de una variable cuando hay una lectura de la variable antes de una asignacin Ecuaciones
LV_TOP(BB)=(LV_BOT(BB)-LV_DEF(BB)) LV_USE(BB) LV_BOT(BB)= s sucesor de BB LV_TOP(S)
Compiladores II
44
Compiladores II
45
Expresiones muy Utilizadas (Very Busy Expression) Una expresin es muy utiliza en un punto p cuando el valor de la expresin se requiere antes que el valor de cualquiera de sus trminos a lo largo de cualquier camino que empieza en p. Ecuaciones
VBE_TOP(BB)=(VBE_BOT(BB)-BVE_DEF(BB)) BVE_USE(BB) VBE_BOT(BB)= s sucesor de BB VBE_TOP(S)
Compiladores II
46
Algoritmos iterativos
Son lentos pero genricos Tipos:
lista de trabajos round robin
Compiladores II
47
Aplicaciones a la Optimizacin de Programas expresiones disponibles (al seguir la ejecucin sigue siendo vlido el resultado obtenido)
Eliminar expresiones redundantes
variables vivas
Reutilizar el espacio de variables. Eliminar variables innecesarias
Ejemplo: Optimizacin Global IF A[1]<0 & J>0 THEN L:=1 ELSE L:=2; J:=2; FOR K:=1 STEP 2 UNTIL J DO BEGIN
A[1]<0
J>0
L:=1
Compiladores II
49
J>0
{J,K}
L:=2 L:=1
J:=2 K:=1
Compiladores II
50
J>0
L:=2 L:=1
J:=2 K:=1
Se puede eliminar L e I Las A[K],A[K+1] no se eliminan pues no se han podido considerar en el clculo de variables vivas
Compiladores II 51
Eliminar J>0 por no utilizarse y saltar al mismo bloque bsico Eliminar A[1]<0 despus de eliminar J>0
J>0
{J:=2} K<2
Compiladores II
52
J:=2 K:=1
A[1+1]:=A[1]+A[1+1]; K=3;
A[2]:=A[1]+A[2]; K=3;
Compiladores II
53