Otimização de Código fonte: Ana Price
• produzir código eficiente
• qualidade do código é medida – pelo tamanho
– pelo tempo de execução
• otimização consome tempo de compilação – compilação cara -> execução barata
software comercial – código não otimizado
-> compilação rápida, execução cara programas de alunos
Otimização de Código
• técnica básica – detectar padrões
– substituí-los por padrões equivalentes mais eficientes
• pontos de otimização – código intermediário – código objeto
• otimizações mais importantes – implementar algoritmo eficiente – utilização eficiente de registradores
Implementação de algoritmo eficiente
• Exemplo:
B - bubble sort, Te = 100 n2 µs Bo - B otimizado, Te = 50 n2 µs Q - Quick Sort, Te = 500 n log2 n µs n 100 1000
B 1s 100s Bo 0.5s 50s Q 0.1s 1.5s
Fontes de Otimização
• loops internos
– remoção de computações loop-invariantes – eliminação de variáveis de indução
• identificação de sub-expressões comuns
• substituição de constantes por seus valores
Otimização de loop
• Exemplo: produto entre dois vetores begin
prod := 0;
i := 1;
do begin
prod := prod + A[i] * B[i];
i := i + 1;
end while i <= 20 end;
Código gerado
(1) prod = 0 (2) i = 1
(3) T1 = 4 * i // endereçamento array A (4) T2 = addr(A) - 4
(5) T3 = T2 [T1 ] // valor de A[i]
(6) T4 = 4 * i // endereçamento array A (7) T2 = addr(B) - 4
(8) T6 = T5 [T4 ] // valor de B[i]
(9) T7 = T3 * T6 // A[i] * B[i]
(10) T8 = prod + T7 (11) prod = T8 (12) T9 := i + 1 (13) i = T9
(14) if i <= 20 goto (3)
Grafo de Fluxo de Controle
• nodos representam código sequencial – blocos básicos
• arcos representam fluxo de controle
• algoritmo para determinação de blocos básicos – determinar os líderes
• primeiro comando é líder
• qualquer comando objetivo de goto é líder
• qualquer comando que segue goto condicional
– blocos são formados pelo líder e os comandos seguintes até o próximo líder
B1 prod = 0 i = 1
B2
T1 = 4 * i T2 = addr(A) - 4 T3 = T2 [T1 ] T4 = 4 * i
T5 = addr(B) - 4 12 comandos no loop T6 = T5 [T4 ]
T7 = T3 * T6 T8 = prod + T7 prod = T8 T9 := i + 1 i = T9
if i <= 20 goto B2
B1 prod = 0 Eliminando atribuições redundantes i = 1
T8 = prod + T7 prod = T8
B2
T1 = 4 * i T2 = addr(A) - 4 T3 = T2 [T1 ] T4 = 4 * i
T5 = addr(B) - 4 10 comandos no loop T6 = T5 [T4 ]
T7 = T3 * T6 prod = prod + T7 i := i + 1
if i <= 20 goto B2
B1 prod = 0 Eliminando sub-expressões comuns i = 1
T1 = 4 * i
B2
T1 = 4 * i T2 = addr(A) - 4 T3 = T2 [T1 ]
T5 = addr(B) - 4 9 comandos no loop T6 = T5 [T1 ]
T7 = T3 * T6 prod = prod + T7 i := i + 1
if i <= 20 goto B2
B1 prod = 0 Movimentação de código:
i = 1 loop-invariantes movidos para fora
B3 T2 = addr(A) - 4 T5 = addr(B) - 4
B2
T1 = 4 * i T3 = T2 [T1 ]
T6 = T5 [T1 ] 7 comandos no loop
T7 = T3 * T6 prod = prod + T7 i := i + 1
if i <= 20 goto B2
Eliminação de variáveis de indução
• i e T1 são variáveis de indução i = 1, 2, ..., 20
T1 = 4 * i
T1 = 4, 8, ..., 80
• após o comando i = i+1, a relação T1 = 4*i - 4 deve ser sempre verdadeira
• logo, substituindo i por T1, o desvio fica if T1 <=76 goto B2
• substituir T1 =4*i por T1=T1+4 e inicializar T1=0
B1 prod = 0 Eliminação de variáveis de indução
B3 T2 = addr(A) - 4 T2 = addr(B) - 4
B4 T1 = 0 B2
T1 = T1 + 4 T3 = T2 [T1 ]
T6 = T5 [T1 ] 6 comandos no loop
T7 = T3 * T6 prod = prod + T7 if T1 <= 76 goto B2
ZOL Duplo acesso MAC
Transformações que preservam a estrutura
• eliminação de sub-expressões comuns a = a + b a = a + b
b = a - d b = a - d c = b + c c = b + c d = a - d d = b
• eliminação de código morto
– se x não é mais referenciado após
x = y+z
, então este comando pode ser removido• troca entre comandos adjacentes independentes t1 = b+c se x e y são diferentes de t1 e t2 = x+y se b e c são diferentes de t2
Transformações algébricas
• eliminar x = x + 0 x = x * 1
• substituir x = y ** 2 x = y * y
Redução em força
• Substituição de operação cara por barata x = 2 * y por x = y + y
L = length (s1 || s2 ) por L = length (s1) + length (s2)
Representação de Blocos Básicos através de Grafos Acíclicos Dirigidos
(GADs)
• identificar sub-expressões comuns num bloco
• identificar entradas:
– nomes usados dentro do bloco mas avaliados fora
• identificar saídas:
– nomes cujos valores são computados dentro do bloco e usados fora do bloco
GAD de bloco básico
• folhas representam variáveis ou constantes
• nodos internos são identificados por operadores
• nodos internos representam valores computados
• Exemplo:
a := b + c +
b c
a
Bloco básico e GAD correspondente
t3
-
*
*
- -
* t6
t1 t2 t4 t5
a b c
t7
+ t1 = a + b t2 = a - b t3 = t1 * t2 t4 = a - c t5 = b - c t6 = t2 * t4 t7 = t6 * t5
Dependências explicitas Paralelismo disponível
Tradução para Assembly
t1 := a + b LOAD a LOAD b
t2 := a - b ADD b SUB c
t3 := t1 * t2 STO t1 STO t5
t4 := a - c LOAD a LOAD t2
t5 := b - c SUB b MULT t4
t6 := t2 * t4 STO t2 MULT t5
t7 := t6 * t5 LOAD t1 STO t7
MULT t2
STO t3
LOAD a
SUB c
STO t4
Custo = 19
Geração do GAD
(incompleto)• Supor instrução num dos formatos:
x := y op z (1)
x := op y (2)
x := y (3)
• Para cada comando do bloco básico faça:
– se o nodo y ainda não foi definido, crie uma folha para y. Faça o mesmo para z, caso (1).
– caso (1): se existe um nodo op com filhos y e z chame-o, também, de x; senão, crie um nodo com nome x.
– caso (2): se existe um nodo op com um único filho y chame-o de x; se não existir, crie e chame-o de x
i0 + +
*
a *
b prod0
t6, prod
t5
t2 t4
t1, t3
t7, i
(1)
20
[ ] [ ] <=
4 1
t1 = 4 * i t6 = prod + t5 t2 = a [t1] prod = t6 t3 = 4 * i t7 = i + 1 t4 = b [t3] i = t7
t5 = t2 * t4 if i <= 20 goto (1)
Ordenação dos nodos
(incompleto)1) crie uma lista L vazia
2) escolha nodo n, que não esteja em L, tal que, se existirem arestas incidentes a n, estas se originam em nodos já em L.
Adicionar n a L. Se não existe tal n, encerra.
3) se: (i) n é o último nodo adicionado a L;
– (ii) a aresta mais à esquerda que se origina em n incide em um nodo interno m que não está em L;
– (iii) todos os predecessores diretos de m estão em L;
– então adicionar m a L e repetir (3);
4) senão, executar (2).
Exemplo
-
*
*
+ - -
*
a b c
t3 n6
t7
t1 t2 t4 t5
lista L t3 t1 t7 t6 t2 t4 (ou t5) t5 (ou t4)
Código intermediário otimizado
t5 = b - c t4 = a - c t2 = a -b t6 = t2 * t4 t7 = t6 * t5 t1 = a + b t3 = t1 * t2
Código objeto otimizado
LOAD b LOAD a
SUB c ADD b
STO t5 MULT t2
LOAD a STO t3
SUB c STO t4 LOAD a SUB b
STO t2 Custo = 16: economia LD/ST MULT t4
MULT t5 STO t7