Compiler ASM – Generador de Assembly Nativo Multi‑arquitectura
Archivo: src/compiler_asm.rs (3.547 líneas)
Este backend de compilación Ahead‑of‑Time genera código ensamblador nativo directamente desde el AST de Forja, sin pasar por bytecode ni JIT. Soporta tres arquitecturas objetivo: x86‑64 Windows, x86‑64 Linux y AArch64 (ARM64), con convenciones de llamada, registro y sintaxis específicas de cada plataforma.
TargetArch — Arquitectura Objetivo
pub enum TargetArch {
X86_64Windows,
X86_64Linux,
AArch64,
}
Métodos de TargetArch
| Método | Firma | Descripción |
detect() | pub fn detect() -> Self | Auto‑detecta la arquitectura en compilación usando cfg!(target_arch) y cfg!(target_os). Prioriza cfg!(windows) para elegir entre MSVC y SystemV. |
name() | pub fn name(&self) -> &str | Retorna el nombre descriptivo: "x86_64-windows", "x86_64-linux", "aarch64". |
from_str() | pub fn from_str(s: &str) -> Option<Self> | Parsea un string como "x86_64-windows", "x86_64-linux", "aarch64" y devuelve el enum. |
syntax_directive() | pub fn syntax_directive(&self) -> &str | Devuelve la directiva de sintaxis: ".intel_syntax noprefix" para x86‑64, ".arch armv8-a" para ARM64. |
section_rodata() | fn section_rodata(&self) -> &str | Sección de solo lectura: ".section .rdata" en Windows, ".section .rodata" en Linux, ".section .rodata" en ARM. |
ret_reg() | fn ret_reg(&self) -> &str | Registro de retorno: rax (x86‑64) o x0 (ARM64). |
ret_reg_32() | fn ret_reg_32(&self) -> &str | Registro de retorno de 32 bits: eax o w0. |
arg_regs() | fn arg_regs(&self) -> &[&str] | Convención de llamada: [rcx, rdx, r8, r9] (Windows x64) o [rdi, rsi, rdx, rcx, r8, r9] (SystemV), [x0..x7] (ARM64). |
tmp_reg() / tmp2_reg() | fn tmp_reg(&self) -> &str | Registros temporales volátiles: r10/r11 (x86‑64), x9/x10 (ARM64). |
fp_reg() / sp_reg() | fn fp_reg(&self) -> &str | Frame pointer (rbp/x29) y stack pointer (rsp/sp). |
shadow_space() | fn shadow_space(&self) -> i32 | Espacio de sombra obligatorio en x64 Windows: 32 bytes. Linux y ARM retornan 0. |
float_reg() | fn float_reg(&self) -> &str | Registro de punto flotante: xmm0 (x86‑64), d0 (ARM64). |
CompilerAsm — Generador de Código
pub struct CompilerAsm {
arch: TargetArch,
output: Vec<String>,
labels: HashMap<String, String>,
register_pool: Vec<&'static str>,
register_available: Vec<bool>,
var_register_map: HashMap<String, &'static str>,
classes_asm_info: HashMap<String, ClaseAsmInfo>,
funciones_declaraciones: HashMap<String, Declaracion>,
string_literals: Vec<String>,
label_counter: usize,
}
Desglose completo de funciones
Constructor y configuración
| Método | Firma | Descripción |
new() | pub fn new() -> Self | Crea un nuevo compilador detectando automáticamente la arquitectura actual. |
with_target() | pub fn with_target(target: TargetArch) -> Self | Crea un compilador para una arquitectura específica (útil para cross‑compilation). |
Registro de variables y pooling
| Método | Descripción |
init_register_pool(arch) -> (Vec<&str>, Vec<bool>) | Inicializa el pool de registros según la arquitectura. x86‑64: [rax, rbx, rcx, rdx, rsi, rdi, r8..r15]. ARM64: [x0..x18]. |
alloc_reg() -> Option<&str> | Busca el primer registro disponible, lo marca como usado y retorna su nombre. |
free_reg(reg: &str) | Marca un registro como disponible nuevamente. |
free_all_regs() | Libera todos los registros del pool. |
alloc_var_reg(nombre: &str) -> Option<&str> | Asigna un registro a una variable Forja. Si ya tenía registro, lo retorna. |
free_var_reg(nombre: &str) | Libera el registro asociado a una variable. |
Generación de código principal
| Método | Descripción |
compilar(programa) -> Result<String, Vec<ErrorForja>> | Punto de entrada. Inyecta cabecera, genera strings en .rdata, runtime functions, clases, y compila declaración por declaración. |
recolectar_clases(declaraciones) | Primera pasada: recolecta definiciones de clase, campos y métodos para construir classes_asm_info. |
generar_strings_rdata() | Genera etiquetas y datos de strings literales en la sección de solo lectura. |
generar_runtime_funciones() | Genera funciones runtime: _forja_itoa, _forja_write_newline, _forja_write_str, _forja_write_int. |
generar_clases_asm(declaraciones) | Genera constructores, getters de campos y tablas de métodos virtuales. |
compilar_declaracion(decl) | Traduce una declaración a ASM: variables (mov reg, val), condicionales (cmp + jcc), bucles, funciones (prólogo/epílogo). |
compilar_expresion_asm(expr) -> String | Traduce una expresión a ASM inline: literales, aritmética, acceso a variables, llamadas. |
compilar_escribir(argumentos) | Genera código para escribir(): literales via lea rcx, [msg], numéricos via _forja_itoa. |
compilar_llamada_funcion(nombre, argumentos) | Evalúa args, los coloca en registros ABI, emite call nombre. Maneja shadow space. |
inline_funcion(nombre, argumentos) | Expande una función inlineable copiando su cuerpo con reemplazo de parámetros. |
Helpers de emisión
| Método | Descripción |
gen_itoa(reg_num) -> Vec<String> | Convierte un entero en registro a string ASCII (división por 10 + push/pop). |
gen_write_newline() | Genera código para imprimir un salto de línea vía syscall o WriteFile. |
gen_write_str_literal(s) | Carga dirección de etiqueta y escribe string por syscall. |
gen_write_int_value(reg_num) | Combina itoa + write_str para imprimir un entero. |
buscar_campo_offset(objeto, miembro) -> i32 | Calcula offset de un campo dentro de la estructura de una clase. |
nueva_etiqueta(prefijo) -> String | Genera una etiqueta única (ej: ".L_if_true_3"). |
emit_line(texto) | Agrega una línea de ASM al buffer de salida. |
Inferencia de tipos ASM
| Función | Descripción |
tipo_forja_a_asm(tipo: &Option<Tipo>) -> TipoAsm | Convierte tipo Forja (Entero, Decimal, etc.) a TipoAsm::I64, F64. |
inferir_tipo_campo_asm(campo) -> TipoAsm | Infere el tipo ASM de un campo de clase. |
tipo_asm_size(tipo) -> i32 | Retorna tamaño en bytes: 8 para I64/F64/Bool/Ptr, 4 para I32. |
es_candidata_inline(decl) -> bool | Determina si una función puede ser inlineada (cuerpo pequeño, sin constructos complejos). |
Pipeline de compilación completo
- Detección:
TargetArch::detect() o with_target() para cross‑compilation. - Recolección: Pasada sobre el AST para recolectar clases y candidatas inline.
- Cabecera: Directivas de sintaxis,
.rdata con strings, funciones runtime. - Clases: Constructores, getters y tablas virtuales.
- Compilación:
compilar_declaracion para cada declaración global. - Expresiones:
compilar_expresion_asm dentro de los cuerpos. - Inline: Expansión de funciones inlineables.
Funciones públicas expuestas
| Función | Descripción |
compilar_a_asm(programa) -> Result<String, Vec<ErrorForja>> | Compila un programa Forja a ASM nativo (detección automática). |
compilar_a_asm_con_target(programa, target) -> Result<String, Vec<ErrorForja>> | Compila a ASM para una arquitectura específica (cross‑compilation). |
⚠️ Limitaciones: El backend ASM es el más cercano al hardware pero también el más verboso. No soporta todas las características de Forja (clases con herencia compleja, pattern matching anidado). Para programas completos se recomienda usar bytecode + VM Fast o LLVM backend.