Aula 18: Geração de Código Intermediário (IR)
Objetivos
- Compreender a necessidade de Representações Intermediárias (IR).
- Estudar o Código de Três Endereços (3AC).
Conteúdo
O “Middle-end” do compilador começa aqui. Depois de validar a semântica, precisamos começar a se preocupar com a tradução para código de máquina, mas sem se prender prematuramente aos detalhes de uma arquitetura específica (como x86 ou ARM).
Representação Intermediária (IR)
Uma linguagem “franca” que serve de ponte entre N front-ends e M back-ends. - Nível Alto (próximo à linguagem fonte): Mantém arrays, objetos. Ex: AST. - Nível Médio: Independente de linguagem e máquina. Ex: 3AC, SSA. - Nível Baixo: Próximo da máquina (registradores, endereços), mas ainda virtual. Ex: LLVM MachineIR.
Código de Três Endereços (3AC)
A forma mais clássica de IR. Cada instrução executa, no máximo, uma operação e atribui a um resultado. Formato geral: x = y op z Isso “quebra” expressões complexas como a = b + c * d em:
t1 = c * d
t2 = b + t1
a = t2
Vantagens: - Simplifica a geração de código (mapeamento 1:1 para Assembly é possível). - Facilita otimizações de reordenação.
Implementação: Quádruplas vs Triplas
Como armazenar x = y op z na memória? 1. Quádruplas: Struct {op, arg1, arg2, result}. Explícita e fácil de mover. 2. Triplas: {op, arg1, arg2}. O resultado é implícito (índice da instrução). Mais compacta, mas difícil de reordenar (mudança de índice quebra referências).
Referências
- Aho, A. V., Lam, M. S., Sethi, R., & Ullman, J. D. (2006). Compilers: Principles, Techniques, and Tools.
- Cooper, K., & Torczon, L. (2011). Engineering a Compiler.