Subsecciones

Optimización de Código

Aunque en esta fase se incluyen toda clase de optimizaciones, es aquí donde se hacen las optimizaciones de código dependientes del sistema objeto. Normalmente se recorre el código generado buscando secuencias de instrucciones que se puedan sustituir por otras cuya ejecución sea mas eficiente. El nombre Peephole optimization hace alusión a esta especie de ``ventana de visión'' que se desplaza sobre el código. En nuestro caso, supongamos que disponemos de una instrucción INC que permite incrementar eficientemente una expresión. Recorremos el código buscando por un patrón "sumar 1" y lo reeemplazamos adecuadamente.

package Peephole::Optimization;

sub transform {
  $target = shift;
  $target =~ s/PUSH 1\nPLUS/INC/g;
}

Otro ejemplo de optimización peephole consiste en reemplazar las operaciones flotantes de división por una constante por la multiplicación por la inversa de la misma (aquí se pueden introducir diferencias en el resultado, debido a la inexactitud de las operaciones en punto flotante y a que, si se trata de un compilador cruzado la aritmética flotante en la máquina en la que se ejecuta el compilador puede ser diferente de la de la máquina que ejecutará el código objeto).


Práctica: Optimización Peephole

  1. Optimice el código generado para la máquina de registros sustituyendo las operaciones de multiplicación y división enteras por una constante que sea potencia de dos (de la forma $ 2^n$) por operaciones de desplazamiento. Repase el capítulo de expresiones regulares. Es posible que aquí quiera emplear una sustitución en la que la cadena de reemplazo sea evaluada sobre la marcha. Si es así, repase la sección 31.1.6. La siguiente sesión con el depurador pretende ilustrar la idea:
    $ perl -de 0
    DB<1> $a = "MUL R2, 16"
    DB<2> $a =~ s/MUL R(\d), (\d+)/($2 == 16)?"SHL R$1, 4":$&/e
    DB<3> p $a
    SHL R2, 4
    DB<5> $a = "MUL R2, 7"
    DB<6> $a =~ s/MUL R(\d), (\d+)/($2 == 16)?"SHL R$1, 4":$&/e
    DB<7> p $a
    MUL R2, 7
    DB<8>
    

  2. El plegado de constantes realizado durante la optimización de código independiente de la máquina (véase la sección 33.11) es parcial. Si los árboles para el producto se hunden a izquierdas, una expresión como a = a * 2 * 3 no será plegada, ya que produce un árbol de la forma

    $ t = TIMES(TIMES(a,2),3)$

    Dado que el algoritmo no puede plegar $ t/1$ tampoco plegará $ t$. Busque en el código objeto secuencias de multiplicaciones por constantes y abrévielas en una. Haga lo mismo para las restantes operaciones.

  3. Dado el siguiente programa:
    $ cat test14.tutu
    int a,b; a = 2; b = a*a+1
    
    El código producido por el traductor para la máquina de registros es:
    1 LOADC R0, 2
    2 STORE  0, R0 # a
    3 LOADM R0, 0 # a
    4 MULTM R0, 0 # a
    5 PLUSC R0, 1 # 1
    6 STORE  1, R0 # b
    
    Se ve que la instrucción de carga LOADM R0, 0 de la línea 3 es innecesaria por cuanto el contenido de la variable a ya está en el registro R0, ya que fué cargada en el registro en la línea 2. Nótese que esta hipótesis no es necesariamente cierta si la línea 3 fuera el objetivo de un salto desde otro punto del programa. Esta condición se cumple cuando nos movemos dentro de un bloque básico: una secuencia de instrucciones que no contiene instrucciones de salto ni es el objetivo de instrucciones de salto, con la excepción de las instrucciones inicial y final. Mejore el código generado intentando detectar patrones de este tipo, eliminando la operación de carga correspondiente.

Casiano Rodríguez León
2013-04-23