Você está na página 1de 12

Pesquisar em Wikiversidade

ltima modificao h 6 anos por Ozymandias

Introduo Teoria dos Compiladores/Gerao e


Otimizao de Cdigo

Gerao de Cdigo
A traduo do cdigo de alto nvel para o cdigo do processador est associada a
traduzir para a linguagem-alvo a representao da rvore gramatical obtida para as
diversas expresses do programa. Embora tal atividade possa ser realizada para a rvore
completa aps a concluso da anlise sinttica, em geral ela efetivada atravs das
aes semnticas associadas aplicao das regras de reconhecimento do analisador
sinttico. Este procedimento denominado traduo dirigida pela sintaxe.
Em geral, a gerao de cdigo no se d diretamente para a linguagem assembly do
processador-alvo. Por convenincia, o analisador sinttico gera cdigo para uma
mquina abstrata, com uma linguagem prxima ao assembly, porm independente de
processadores especficos. Em uma segunda etapa da gerao de cdigo, esse cdigo
intermedirio traduzido para a linguagem assembly desejada. Dessa forma, grande
parte do compilador reaproveitada para trabalhar com diferentes tipos de
processadores.
Vrias tcnicas e vrias tarefas se renem sob o nome de Otimizao. Alguns autores da
literatura consideram que, para qualquer critrio de qualidade razovel, impossvel
construir um programa otimizador, isto , um programa que recebe como entrada um
programa P e constri um programa P equivalente que o melhor possvel, segundo o
critrio considerado. O que se pode construir so programas que melhoram outros
programas, de maneira que o programa P , na maioria das vezes, melhor, segundo o
critrio especificado do que o programa P original. A razo para essa impossibilidade a
mesma que se encontra quando se estuda, por exemplo em LFA (Linguagens Formais e
Autmatos), o problema da parada: um programa (procedimento, mquina de Turing,
etc.) no pode obter informao suficiente sobre todas as possveis formas de execuo
de outro programa (procedimento, mquina de Turing, etc.).

Normalmente, muito fcil fazer uma otimizao em um programa, ou seja, uma


transformao que o transforma em outro melhor. O difcil sempre obter a informao
necessria que garante que a otimizao pode realmente ser aplicada, sem modificar em
nenhum caso o funcionamento do programa.
No prtico tentar otimizar um programa tentando sucessivamente eliminar todos os
seus comandos, um de cada vez. Note que as condies para cada eliminao
dependem do comando, de sua posio, e, de certa maneira, de todos os comandos
restantes do programa. Para construir um otimizador de utilidade na prtica, faz-se
necessrio identificar oportunidades para otimizao que sejam produtivas em situaes
correntes.
Outro exemplo de otimizao que citado freqentemente a retirada de comandos de
um comando de repetio (um loop). Por exemplo, um comando cujo efeito
independente do loop, pode valer a pena retir-lo do loop, para que ele seja executado
apenas uma vez, em vez das muitas vezes que se presume que ser executado o cdigo
de dentro do loop.
Depende muito da finalidade de um compilador o conjunto de otimizaes que ele deve
oferecer. Um compilador usado em um curso introdutrio de programao no precisa
de otimizao, porque os programas so executados quase sempre apenas uma vez.
(Em vez de otimizao, este compilador deveria dar boas mensagens de erro, que
pudessem auxiliar os principiantes na linguagem.) Por outro lado, um programa que vai
ser compilado uma vez e executado muitas vezes deve ser otimizado tanto quanto
possvel. Neste caso esto programas de simulao, de previso do tempo, e a maioria
das aplicaes numricas.
Um outro problema na otimizao de cdigo para um compilador a quantidade de
informao que se deseja manipular. Pode-se examinar otimizaes locais (em trechos
pequenos de programas, por exemplo trechos sem desvios, ou seja, trechos em linha
reta), otimizaes em um nvel intermedirio (as otimizaes so consideradas apenas
em funes, mdulos, ou classes, dependendo da linguagem) e otimizaes globais (que
consideram as inter-relaes de todas as partes de um programa). A maioria dos
compiladores oferece algumas otimizaes do primeiro tipo, possivelmente combinadas
com a fase de gerao de cdigo, e quando muito algumas otimizaes de nvel
intermedirio.
A maneira de tratar a otimizao pode ser extremamente pragmtica. Em um programa
grande, a execuo gasta 90% em 10% do cdigo, e 10% do tempo nos 90% do cdigo

restantes (A literatura menciona valores de 90%-10% at 70%-30%.). Isto acontece porque


em geral um programa constitudo de inicializaes e finalizaes, entre as quais se
encontra um conjunto de vrios loops aninhados. O tempo maior de execuo (os 90%)
gasto no loop mais interno (os 10%). Existem ferramentas que registram o perfil de
execuo do programa (profilers), permitindo a identificao dos trechos mais
executados, e a otimizao pode se concentrar nestes trechos, ignorando para fins de
otimizao o restante do programa. Por essa razo muitos compiladores oferecem
opes de compilao que podem ser ligadas e desligadas no cdigo fonte, indicando
para o compilador os trechos que o programador considera importantes o suficiente para
serem otimizados. Por estas razes, muito do trabalho no desenvolvimento de tcnicas
de otimizao dedicado aos loops.

Cdigo intermedirio
A linguagem utilizada para a gerao de um cdigo em formato intermedirio entre a
linguagem de alto nvel e a linguagem assembly deve representar, de forma independente
do processador para o qual o programa ser gerado, todas as expresses do programa
original. Duas formas usuais para esse tipo de representao so a notao posfixa e o
cdigo de trs endereos.

Cdigo de trs endereos


O cdigo de trs endereos composto por uma seqncia de instrues envolvendo
operaes binrias ou unrias e uma atribuio. O nome "trs endereos est associado
especificao, em uma instruo, de no mximo trs variveis: duas para os operadores
binrios e uma para o resultado. Assim, expresses envolvendo diversas operaes so
decompostas nesse cdigo em uma srie de instrues, eventualmente com a utilizao de
variveis temporrias introduzidas na traduo. Dessa forma, obtm-se um cdigo mais
prximo da estrutura da linguagem assembly e, conseqentemente, de mais fcil converso
para a linguagem-alvo.
Uma possvel especificao de uma linguagem de trs endereos envolve quatro tipos
bsicos de instrues: expresses com atribuio, desvios, invocao de rotinas e
acesso indexado e indireto.
Instrues de atribuio so aquelas nas quais o resultado de uma operao
armazenado na varivel especificada esquerda do operador de atribuio, aqui
denotado por:=. H trs formas para esse tipo de instruo. Na primeira, a varivel

recebe o resultado de uma operao binria:


x := y op z

O resultado pode ser tambm obtido a partir da aplicao de um operador unrio:


x := op y

Na terceira forma, pode ocorrer uma simples cpia de valores de uma varivel para outra:
x := y

Por exemplo, a expresso em C


a = b + c * d;

seria traduzida nesse formato para as instrues:

_t1 := c * d
a := b + _t1

As instrues de desvio podem assumir duas formas bsicas. Uma instruo de desvio
incondicional tem o formato
goto L

onde L um rtulo simblico que identifica uma linha do cdigo. A outra forma de desvio
o desvio condicional, com o formato
if x opr y goto L

onde opr um operador relacional de comparao e L o rtulo da linha que deve ser
executada se o resultado da aplicao do operador relacional for verdadeiro; caso
contrrio, a linha seguinte executada.
Por exemplo, a seguinte iterao em C
while (i++ <= k)

x[i] = 0;
x[0] = 0;

poderia ser traduzida para


_L1: if i > k goto _L2
i := i + 1
x[i] := 0
goto _L1

_L2: x[0]:= 0
A invocao de rotinas ocorre em duas etapas. Inicialmente, os argumentos do
procedimento so "registrados com a instruo param; aps a definio dos argumentos, a
instruo call completa a invocao da rotina. A instruo return indica o fim de execuo de
uma rotina. Opcionalmente, esta instruo pode especificar um valor de retorno, que pode ser
atribudo na linguagem intermediria a uma varivel como resultado de call.
Por exemplo, considere a chamada de uma funo f que recebe trs argumentos e
retorna um valor:
f(a, b, c);

Neste exemplo em C, esse valor de retorno no utilizado. De qualquer modo, a


expresso acima seria traduzida para
param a
param b
param c
_t1 := call f,3

onde o nmero aps a vrgula indica o nmero de argumentos utilizados pelo


procedimento f. Com o uso desse argumento adicional possvel expressar sem
dificuldades as chamadas aninhadas de procedimentos.
O ltimo tipo de instruo para cdigos de trs endereos refere-se aos modos de
endereamento indexado e indireto. Para atribuies indexadas, as duas formas bsicas
so
x := y[i]

x[i] := y

As atribuies associadas ao modo indireto permitem a manipulao de endereos e


seus contedos. As instrues em formato intermedirio tambm utilizam um formato
prximo quele da linguagem C:
x := &y
w := *x
*x := z

A representao interna das instrues em cdigos de trs endereos d-se na forma de


armazenamento em tabelas com quatro ou trs colunas. Na abordagem que utiliza
qudruplas (as tabelas com quatro colunas), cada instruo representada por uma
linha na tabela com a especificao do operador, do primeiro argumento, do segundo
argumento e do resultado
Para algumas instrues, como aquelas envolvendo operadores unrios ou desvio
incondicional, algumas das colunas estariam vazias.

Na outra forma de representao, por triplas, evita a necessidade de manter nomes de


variveis temporrias ao fazer referncia s linhas da prpria tabela no lugar dos
argumentos. Nesse caso, apenas trs colunas so necessrias, uma vez que o resultado
est sempre implicitamente associado linha da tabela.

Notao posfixa
A notao tradicional para expresses aritmticas, que representa uma operao binria
na forma x+y, ou seja, com o operador entre seus dois operandos, conhecida como
notao infixa. Uma notao alternativa para esse tipo de expresso a notao posfixa,
tambm conhecida como notao polonesa, na qual o operador expresso aps seus
operandos.
O atrativo da notao posfixa que ela dispensa o uso de parnteses. Por exemplo, as
expresses
a*b+c;
a*(b+c);
(a+b)*c;
(a+b)*(c+d);

seriam representadas nesse tipo de notao respectivamente como


ab*c+
abc+*
ab+c*
ab+cd+*

Instrues de desvio em cdigo intermedirio usando a notao posfixa assumem a


forma
L jump
x y L jcc

para desvios incondicionais e condicionais, respectivamente. No caso de um desvio


condicional, a condio a ser avaliada envolvendo x e y expressa na parte cc da prpria
instruo. Assim, jcc pode ser uma instruo entre jeq (desvio ocorre se x e y forem
iguais), jne (se diferentes), jlt (se x menor que y), jle (se x menor ou igual a y), jgt (se x
maior que y) ou jge (se x maior ou igual a y).
Expresses em formato intermedirio usando a notao posfixa podem ser
eficientemente avaliadas em mquinas baseadas em pilhas, tambm conhecidas como
mquinas de zero endereos. Nesse tipo de mquinas, operandos so explicitamente
introduzidos e retirados do topo da pilha por instrues push e pop, respectivamente.
Alm disso, a aplicao de um operador retira do topo da pilha seus operandos e retorna
ao topo da pilha o resultado de sua aplicao.
Por exemplo, a avaliao da expresso a*(b+c) em uma mquina baseada em pilha
poderia ser traduzida para o cdigo
push a
push b
push c
add
mult

Otimizao de cdigo
A etapa final na gerao de cdigo pelo compilador a fase de otimizao. Como o
cdigo gerado atravs da traduo orientada pela sintaxe contempla expresses

independentes, diversas situaes contendo seqncias de cdigo ineficiente podem


ocorrer. O objeto da etapa de otimizao de cdigo aplicar um conjunto de heursticas
para detectar tais seqncias e substitu-las por outras que removam as situaes de
ineficincia.
As tcnicas de otimizao que so usadas em compiladores devem, alm de manter o
significado do programa original, ser capazes de capturar a maior parte das
possibilidades de melhoria do cdigo dentro de limites razoveis de esforo gasto para
tal fim. Em geral, os compiladores usualmente permitem especificar qual o grau de
esforo desejado no processo de otimizao. Por exemplo, em gcc h opes na forma O... que do essa indicao, desde O0 (nenhuma otimizao) at -O3 (mxima
otimizao, aumentando o tempo de compilao), incluindo tambm uma opo -Os,
indicando que o objetivo reduzir a ocupao de espao em memria.
Algumas heursticas de otimizao so sempre aplicadas pelos compiladores. Por
exemplo, se a concatenao de cdigo gerado por duas expresses no programa original
gerou uma situao de desvio incondicional para a linha seguinte, como em
(a)
goto _L1

_L1: (b)
esse cdigo pode ser seguramente reduzido com a aplicao da tcnica de eliminao
de desvios desnecessrios, resultando em
(a)

_L1: (b)
Outra estratgia de otimizao elimina os rtulos no referenciados por outras
instrues do programa. Assim, se o rtulo _L1 estivesse sendo referenciado
exclusivamente por essa instruo de desvio, ele poderia ser eliminado em uma prxima
aplicao das estratgias de otimizao.
As tcnicas de otimizao podem ser classificadas como independentes de mquina,
quando podem ser aplicadas antes da gerao do cdigo na linguagem assembly, ou
dependentes de mquina, quando aplicadas na gerao do cdigo assembly.
A otimizao independente de mquina tem como requisito o levantamento dos blocos

de comandos que compem o programa. Essa etapa da otimizao conhecida como a


anlise de fluxo, que por sua vez contempla a anlise de fluxo de controle e a anlise de
fluxo de dados. Estratgias que podem ser aplicadas, analisando um nico bloco de
comandos so denominadas estratgias de otimizao local, enquanto aquelas que
envolvem a anlise simultnea de dois ou mais blocos so denominadas estratgias de
otimizao global.
Algumas estratgias bsicas de otimizao, alm da j apresentada eliminao de
desvios desnecessrios, so apresentadas a seguir.
A estratgia de eliminao de cdigo redundante busca detectar situaes onde a
traduo de duas expresses gera instrues cuja execuo repetida no tem efeito. Por
exemplo, em
x := y
...
x := y

se no h nenhuma mudana no valor de y entre as duas instrues, ento a segunda


instruo poderia ser eliminada. O mesmo aconteceria se a segunda instruo fosse
y := x

e o valor de x no fosse alterado entre as duas instrues.


Outra estratgia bsica a eliminao de cdigo no-alcanvel, ou cdigo morto. Por
exemplo, se a seguinte seqncia de cdigo fosse gerada por um conjunto de expresses
...
goto _L1
x := y

_L1: ...
a instruo contendo a atribuio de y a x nunca poderia ser executada, pois precedida
de um desvio incondicional e no o destino de nenhum desvio, pois no contm um
rtulo na linha. Assim, essa linha poderia ser eliminada e provocar posteriormente a
aplicao da estratgia de eliminao de desvios desnecessrios.
O uso de propriedades algbricas outra estratgia de otimizao usualmente aplicada.

Nesse caso, quando o compilador identifica que uma expresso aritmtica foi reduzida a
x=0 ou 0=x ou x-0 ou x*1 ou 1*x ou x/1, ento ele substitui a expresso simplesmente por
x. Outra classe de propriedades algbricas que utilizada tem por objetivo substituir
operaes de alto custo de execuo por operaes mais simples, como
2.0*x = x+x x2 = x*x x/2 = 0.5*x
Particularmente no ltimo caso, se x for uma varivel inteira a diviso por dois pode ser
substituda por um deslocamento da representao binria direita de um bit.
Genericamente, a diviso inteira por 2n equivale ao deslocamento direita de n bits na
representao binria do dividendo. Da mesma forma, a multiplicao inteira por
potncias de dois pode ser substituda por deslocamento de bits esquerda.
A utilizao de propriedades algbricas permite tambm o reuso de subexpresses j
computadas. Por exemplo, a traduo direta das expresses
a = b + c;
e = c + d + b;

geraria o seguinte cdigo intermedirio:


a := b + c
_t1 := c + d
e := _t1 + b

No entanto, o uso da comutatividade e associatividade da adio permite que o cdigo


gerado seja reduzido usando a eliminao de expresses comuns, resultando em
a := b + c
e := a + d

Diversas oportunidades de otimizao esto associadas anlise de comandos


iterativos. Uma estratgia a movimentao de cdigo, aplicado quando um clculo
realizado dentro do lao na verdade envolve valores invariantes na iterao. Por exemplo,
o comando
while (i < 10*j) {
a[i] = i + 2*j;
++i;
}

estaria gerando um cdigo intermedirio equivalente a


_L1: _t1 := 10 * j
if i >= _t1 goto _L2
_t2 := 2 * j
a[i] := i + _t2
i := i + 1
goto _L1
_L2:

...

No entanto, a anlise de fluxo de dados mostra que o valor de j no varia entre iteraes.
Assim, o compilador poderia mover as expresses que envolvem exclusivamente
constantes na iterao para fora do lao, substituindo esse cdigo por
_t1:= 10 * j
_t2 := 2 * j
_L1: if i >= _t1 goto _L2
a[i] := i + _t2
i := i + 1
goto _L1
_L2:

...

Um exemplo de otimizao dependente de mquina pode ser apresentado para a


expresso
x := y + K

onde K alguma constante inteira. Na traduo para o cdigo assembly de um


processador da famlia 68K, a forma genrica poderia ser algo como
MOVE.L y,D0
ADDI.L #K,D0
MOVE.L D0,x

No entanto, se o compilador verificasse que o valor de K fosse uma constante entre 1 e 8,


ento a segunda instruo assembly poderia ser substituda por ADDQ.L, que utilizaria
em sua codificao apenas dois bytes ao invs dos seis bytes que seriam requeridos
pela instruo ADDI.L.

Esta pgina somente um esboo. Ampliando-a voc ajudar a melhorar a Wikiversidade.

Wikiversidade Mvel

Normal

Contedo disponibilizado nos termos da CC BY-SA 3.0 , salvo indicao em contrrio.


Termos de Uso

Privacidade