# Análise e otimização de código

Análise de fluxo de dados, propagação de constantes e eliminação de código morto num bloco básico.

Página: https://resumos.rgo.pt/cadeiras/c/otimizacao-codigo/

Otimizar é transformar o programa para correr mais rápido (ou ocupar menos espaço) **sem lhe mudar o significado observável**. Para transformar em segurança, o compilador primeiro analisa: calcula, para cada ponto do programa, factos como “que definições chegam aqui” ou “que variáveis estão vivas”. Só depois reescreve, apoiado nesses factos.

## Análise de fluxo de dados

A análise propaga factos pelos blocos do grafo de fluxo até estabilizar (**ponto fixo**): cada bloco combina os factos dos antecessores, aplica o seu efeito e passa o resultado aos sucessores, repetindo até nada mudar. Duas análises clássicas:

*   **Variáveis vivas**: uma variável está viva num ponto se o seu valor atual pode ser lido no futuro. Decide o que manter em registos e o que pode ser descartado.
*   **Definições que alcançam**: que atribuições podem ter produzido o valor lido em cada uso. Sustenta a propagação de constantes e de cópias.

```
t1 = 5       # t1 viva? só até à linha 2
t2 = t1 + 3  # t2 viva? só até à linha 3
x = t2       # x viva à saída (lê-se fora)
y = 10       # y morta à saída (ninguém lê)
```

Pergunta para a frente: este valor ainda vai ser lido? `y` não, por isso a linha 4 pode sair.

```
t1 = 5       # chega a t1 = 5 ao uso na linha 2? sim, única
t2 = t1 + 3  # chega a t2 = t1 + 3 ao uso na linha 3? sim, única
x = t2       # chega ao fim? sim, via x
```

Pergunta para trás: de onde veio este valor? Uma única definição a alcançar cada uso é o que autoriza substituir o nome pelo valor.

## Exemplo: propagar e eliminar

Bloco básico de entrada:

```
t1 = 5
t2 = t1 + 3
x = t2
y = 10
```

A análise de definições que alcançam diz que, no uso de `t1`, a única definição possível é `t1 = 5`. A **propagação de constantes** substitui: `t2 = 5 + 3`, que o **dobramento de constantes** avalia em `t2 = 8`. Propaga outra vez: `x = 8`. Agora `t1` e `t2` não têm nenhum uso restante, por isso a **eliminação de código morto** remove as duas primeiras instruções. E `y = 10`? Se `y` não está viva à saída do bloco (nenhum sucessor no grafo a lê), remove-se também. Resultado:

```
x = 8
```

Confirma com o grafo de fluxo: o bloco continua a definir exatamente as variáveis vivas à saída com os mesmos valores, por isso nenhum caminho do programa distingue o antes do depois. É este o teste de cada otimização: os valores observáveis nos pontos de saída mantêm-se.

![Bloco antes e depois da otimização: antes quatro instruções com as três mortas riscadas, depois só x igual a 8.](https://resumos.rgo.pt/cadeiras/c/otimizacao-codigo/figura-1.svg)

Lê o antes com as linhas riscadas: tudo o que morreu na análise sai. O depois é o programa que corre, com o mesmo `x = 8` observável.

A mesma otimização feita por um programa, sobre o bloco de entrada. Muda os valores e vê o resultado acompanhar.

```python
bloco = ["t1 = 5", "t2 = t1 + 3", "x = t2", "y = 10"]
constantes = {}
saida = []
for inst in bloco:
    destino, expr = [p.strip() for p in inst.split("=", 1)]
    for nome, valor in constantes.items():
        expr = expr.replace(nome, str(valor))
    try:
        valor = eval(expr, {"__builtins__": {}}, {})
        constantes[destino] = valor
        expr = str(valor)
    except (NameError, SyntaxError):
        constantes.pop(destino, None)
    saida.append(f"{destino} = {expr}")
vivas = {"x"}
final = [inst for inst in saida if inst.split("=")[0].strip() in vivas]
print(final)
```

O programa imprime `['x = 8']`. Segue o dicionário `constantes`: cada definição constante entra nele e reescreve os usos seguintes, até só restar o que está vivo. É uma dobragem ingénua (sem grafo de fluxo), mas mostra o mecanismo que a análise sustenta.

Otimizar cedo demais esconde erros

Aplica as otimizações sobre código intermédio já validado e confirma cada transformação no grafo de fluxo. No projeto, depura primeiro com as otimizações desligadas: um erro no código gerado com otimizações ligadas pode estar na otimização ou no código original, e sem a versão simples não distingues.
