Você está na página 1de 19

Otimização de Código

GCC130 – Compiladores
Contexto
• As etapas de Geração de Código Intermediário e de Geração de
Código realizam traduções considerando instruções individuais.
• Podem existir ineficiências: custos de tempo e armazenamento
• O Otimizador aplica um conjunto de heurísticas para identificar
padrões ineficientes na estrutura do código que podem ser alvo de
TRANSFORMAÇÕES.
• Estas transformações são chamadas de OTIMIZAÇÕES, muito embora
não seja possível garantir que tragam, de fato, melhorias de
desempenho.
Tipos de Otimizadores
• Dependentes de Máquina
• Realizadas sobre o resultado do Gerador de Código
• Conhecem detalhes sobre os conjuntos de instruções das máquinas-alvo
• Específicos

• Independentes de Máquina
• Realizadas sobre o resultado do Gerador de Código Intermediário
• Desconhecem detalhes sobre os conjuntos de instruções das máquinas-alvo
• Genéricos
Tipos de Otimizadores
• Dependentes de Máquina
• Realizadas sobre o resultado do Gerador de Código
• Conhecem detalhes sobre os conjuntos de instruções das máquinas-alvo
• Específicos

• Independentes de Máquina
• Realizadas sobre o resultado do Gerador de Código Intermediário
• Desconhecem detalhes sobre os conjuntos de instruções das máquinas-alvo
• Genéricos

Compiladores que realizam a etapa de Otimização são chamados de Compiladores Otimizantes


Análise de Fluxo
• O processo para analisar o código para buscar oportunidades de
melhorias é chamado de ANÁLISE DE FLUXO
• Duas etapas:
• Análise de Fluxo de Controle
• Análise de Fluxo de Dados
Ger. Cod. Cód. de 3 Endereços Cód. Int. Otimizado Gerador de
Otimizador
Intermediário Código

Análise de Fluxo Análise de Fluxo


Otimização
de Controle de Dados
Análise de Fluxo de Controle
• Inicialmente o código é segmentado em blocos de instruções.
• Análise de Fluxo de Controle
• Entrada: Código Intermediário
• Saída: Particionamento do código intermediário em blocos básicos
• Blocos Básicos são conjuntos de instruções que necessariamente
serão executadas em sequência.
• São iniciados por instruções iniciais de um procedimento, uma instrução alvo
de um comando de desvio, e instruções imediatamente seguintes a um
comando de desvio.
• São encerrados na instrução imediatamente anterior a uma próxima instrução
inicial de bloco.
Exemplo
unsigned int fib(unsigned int m) 1: receive m(val)
{unsigned int f0=0, f1=1, f2, i; 2: f0  0
if (m <= 1) { 3: f1  1
return m; 4: if m <= 1 goto L3
} 5: i  2
else { 6: L1: if i <=m goto L2
for (i=2, i <=m, i++) { 7: return f2
f2=f0+f1; 8: L2: f2  f0 + f1
f0=f1; 9: f0  f1
f1 =f2;} 10: f1  f2
return f2; } 11: i  i+1
} 12: goto L1
13: L3: return m
Exemplo
unsigned int fib(unsigned int m) 1: receive m(val)
{unsigned int f0=0, f1=1, f2, i; 2: f0  0
if (m <= 1) { 3: f1  1
return m; 4: if m <= 1 goto L3
} 5: i  2
else { 6: L1: if i <=m goto L2
for (i=2, i <=m, i++) { 7: return f2
f2=f0+f1; 8: L2: f2  f0 + f1
f0=f1; 9: f0  f1
f1 =f2;} 10: f1  f2
return f2; } 11: i  i+1
} 12: goto L1
13: L3: return m
Exemplo
unsigned int fib(unsigned int m) 1: receive m(val)
{unsigned int f0=0, f1=1, f2, i; B0 2: f0  0
if (m <= 1) { 3: f1  1
return m; 4: if m <= 1 goto L3
} B1 5: i  2
else { B2 6: L1: if i <=m goto L2
for (i=2, i <=m, i++) { B3 7: return f2
f2=f0+f1; 8: L2: f2  f0 + f1
f0=f1; 9: f0  f1
f1 =f2;} B4 10: f1  f2
return f2; } 11: i  i+1
} 12: goto L1
B5 13: L3: return m
Processo de Otimização
• Após a identificação dos blocos básicos, deve ser criado um
DIAGRAMA DE FLUXO DE CONTROLE.
• São adicionados um bloco de ENTRADA e um de SAÍDA. Para garantir que o
procedimento/programa tenha apenas um ponto de entrada e saída.
• São adicionadas arestas interligando os blocos conforme as possibilidades de
fluxo de execução
ENTRADA

Exemplo 1: receive m(val)


B0 2: f0  0
3: f1  1
unsigned int fib(unsigned int m) 4: if m <= 1 goto L3

{unsigned int f0=0, f1=1, f2, i;


if (m <= 1) { B1 5: i 2 B5 13: L3: return m
return m;
} B2 6: L1: if i <=m goto L2

else {
for (i=2, i <=m, i++) { B3 7: return f2 8: L2: f2  f0 + f1
9: f0  f1
f2=f0+f1;
B4 10: f1  f2
f0=f1; 11: i  i+1
f1 =f2;} 12: goto L1
return f2; }
}
SAÍDA
Análise de Fluxo de dados
• Analisa a definição e uso de dados em um programa.

B0 X= 2

B1 T1 = 4 + X

B2 T2 = 1 + d[T1] B3 T3 = 4 + X
Análise de Fluxo de dados
• Analisa a definição e uso de dados em um programa.

DEFINIÇÃO
B0 X= 2

PONTO DE
B1 T1 = 4 + X AVALIAÇÃO

PONTO DE PONTO DE
B2 T2 = T1 REFERÊNCIA B3 T3 = 4 + X AVALIAÇÃO
Otimizações
• Conjunto de heurísticas que buscam padrões conhecidos que
representam oportunidades de melhorias
• Podem ser globais ou locais
• Locais: Resultante de análise em blocos individuais
• Globais: Resultante de análise em dois ou mais blocos
Exemplos de Otimizações Independentes de
Máquina
• Eliminação de Subexpressões Comuns
• Eliminação de Propagação de Cópias
• Eliminação de Código Morto
• Movimentação de Código
Eliminação de Subexpressões Comuns
• Uma instrução E é dita uma subexpressão comum se o valor de E já
foi previamente computado e seu valor não foi alterado. Assim, E
pode ser removido sem prejuízo ao código.

(1) T1 = a+1; (1) T1 = a+1;


(2) (1) T2 = X[T1]; (2) (1) T2 = X[T1];
(3) (1) T3 = a+1; (3) T4 = T3+2;
(4) (1) T4 = T3+2;
Propagação de Cópias
• Propagação de cópias consiste no encadeamento desnecessário de
operações de cópia.

(1) u:= v (1) u:= v


...

...
(2) w:= u (2) w:= v
Código Morto
• Instruções inacessíveis
• Resultados que não são utilizados

T=0
Inst
Inst (1) u:= v
IF (T>0) GOTO B3

...
(2) w:= v
Movimentação de Código
• Consiste em identificar laços que possuam operações que podem ser
movidas para fora do laço.

(1) WHILE (X>N+1) (1) T1 = N+1


(2) WHILE (X>T1)

Você também pode gostar