Mid-Level IR en SSA (ir.rs)
Archivo: src/ir.rs (462 líneas)
¿Por qué existe?
Define la representación intermedia (IR) en forma SSA (Static Single Assignment) que conecta el AST con el bytecode. En SSA, cada variable se asigna exactamente una vez, y los φ-nodes se encargan de fusionar valores en las uniones de control flow (join points). Esta forma simplifica el análisis y la optimización del código al eliminar la distinción entre asignaciones y usos.
Arquitectura / Estructuras clave
El IR se compone de identificadores numéricos (ValueId, BlockId, SymId), instrucciones Inst, bloques básicos BasicBlock, funciones SSA SsaFunction y un programa completo IrProgram con su tabla de símbolos.
| Componente | Descripción |
|---|---|
ValueId / BlockId / SymId | Alias de usize que identifican valores, bloques básicos y símbolos respectivamente |
IrType | Tipos del IR: Int, Float, Bool, Ptr, Void |
Inst | Enumeración de instrucciones: constantes, Param, Phi, aritmética, comparación, lógica, Load/Store/Alloca, Jump/Branch/Return, Call, y operaciones de objetos y arrays |
BasicBlock | Secuencia de instrucciones sin branches internos; incluye id, instructions y un terminator |
Terminator | Instrucción final que define el flujo de control: Jump, Branch, Return o Unreachable |
SsaFunction | Función SSA: nombre, tipo de retorno, bloques, bloque entry, número y tipos de parámetros |
IrProgram | Programa completo: funciones + tabla de símbolos |
SymbolTable | Interning de nombres a SymId con intern() / name() |
IrBuilder | Builder que emite instrucciones (emit_*), crea bloques (new_block) y terminadores (terminate_*), y construye SsaFunction con build_function |
MemIdx | Índice de un slot de memoria de variable en el scope (para Load/Store) |
Cómo se integra
Ocupa el centro del pipeline de compilación:
AST → (IrConstructor) → IR SSA → (IrOptimizer) → IR optimizado → (IrToBytecode) → Bytecode El IrBuilder es la interfaz que ir_constructor.rs usa para bajar el AST a IR; ir_ssa.rs enriquece este IR con dominadores y φ-nodes; y ir_to_bytecode.rs lo consume para emitir opcodes.
ValueId corresponde a una única definición estática, lo que hace los análisis de alcance (liveness, dominancia) triviales y habilita optimizaciones que son difíciles en una representación mutante.Inst (objetos, arrays, saltos en terminadores) existen en la enumeración pero el constructor y el conversor a bytecode aún no las emiten completamente; están marcadas con #![allow(dead_code)].