Uops – Micro‑Operaciones del Backend

Archivo: src/uops.rs896 líneas

Este módulo define la unidad mínima de trabajo que la capa JIT y el backend ASM del compilador Forja traducen a código máquina nativo. Cada Uop (micro‑operation) representa una instrucción de nivel muy bajo que puede mapearse directamente a una o más instrucciones ensamblador reales según la arquitectura objetivo.

Motivación


Enum Uop — 52 variantes

Operaciones de stack (5)

VarianteDescripción
PushEntero(i64)Apila un entero de 64 bits
PushDecimal(f64)Apila un número de punto flotante
PushTexto(Arc<str>)Apila una cadena de texto (Arc compartido)
PushBooleano(bool)Apila un valor booleano
PushNuloApila el valor nulo
PopDesapila el valor del tope
DupDuplica el valor en el tope del stack

Operaciones de variables (3)

VarianteDescripción
LoadIdx(usize)Carga el valor de la variable en posición idx al stack
StoreIdx(usize)Almacena el valor del tope del stack en la variable idx
DeclareVar(usize)Declara una nueva variable en posición idx

Aritmética (12)

VarianteDescripción
Add / Sub / Mul / DivOperaciones aritméticas genéricas (type dispatch)
AddInt / AddFloatSuma especializada para entero o flotante
SubInt / SubFloatResta especializada para entero o flotante
MulInt / MulFloatMultiplicación especializada para entero o flotante
DivInt / DivFloatDivisión especializada para entero o flotante

Control de flujo (3)

VarianteDescripción
Jump(usize)Salto incondicional a la posición (label) especificada
JumpSiFalso(usize)Salto condicional: salta si el tope del stack es falso
HaltDetiene la ejecución

Funciones (3)

VarianteDescripción
Call(String, usize)Llama a una función por nombre con N argumentos
ReturnRetorna de la función actual
FunctionDef(String, Vec<String>)Define una función: nombre y lista de parámetros

Objetos (4)

VarianteDescripción
NewObject(String)Crea una nueva instancia de la clase especificada
SetField(String)Establece el valor de un campo en un objeto
GetField(String)Obtiene el valor de un campo de un objeto
CallMethod(String, usize)Llama a un método por nombre con N argumentos

Arreglos y mapas (6)

VarianteDescripción
ArrayNew(usize)Crea un nuevo arreglo con capacidad para N elementos
ArrayGetObtiene un elemento del arreglo por índice
ArraySetEstablece un elemento del arreglo por índice
ArrayLenObtiene la longitud del arreglo
MapNew(usize)Crea un nuevo mapa con capacidad para N pares
MapGet / MapSetObtiene o establece un valor en el mapa por clave

Built-ins e I/O (4)

VarianteDescripción
ParseIntConvierte string a entero (pop string, push i64)
TiempoActualObtiene el timestamp Unix actual
PrintImprime el valor del tope del stack
ReadLineLee una línea de la entrada estándar

Comparación y lógica (8)

VarianteDescripción
Igual / DiferenteComparación de igualdad/desigualdad
Menor / MayorComparación menor/mayor que
MenorIgual / MayorIgualComparación menor/mayor o igual que
Y / OConjunción y disyunción lógica
NoNegación lógica

Micro-operaciones de expansión (7)

VarianteDescripción
PrepCall(usize)Prepara el frame para llamada a función (N = número de args)
ResolveMethod(String)Resuelve método en objeto (inline cache)
LoadSelfCarga self/este en el tope del stack
StorePop(usize)Pop + Store combinado: almacena y desapila
LoadPush(usize)Load + Push fusionado
DeclareInit(usize)Declara variable y asigna valor inicial en un solo uop
TryPropagación de errores (expr?)

Optimizaciones de uops (3)

VarianteDescripción
IncrVar(usize)vars[idx] += 1 — incremento unitario fusionado
AddAssign(usize, i64)vars[idx] += n — suma con constante fusionada
SubAssign(usize, i64)vars[idx] -= n — resta con constante fusionada

Exacto (BigDecimal) (10)

VarianteDescripción
PushExacto(i128, u32)Apila un número exacto (coeficiente + escala)
AddExact / SubExact / MulExact / DivExactOperaciones aritméticas exactas
IgualExact / MenorExact / MayorExactComparaciones exactas
EnteroAExacto / DecimalAExactoConversión de tipos a Exacto

Funciones nativas y sockets (2)

VarianteDescripción
CallNative(Arc<str>, usize)Llama a una función nativa registrada en la VM
SocketPoll(Arc<str>)Polling no bloqueante de socket

Marcador (1)

VarianteDescripción
Label(usize)Marcador de posición (no ejecuta, usado como destino de saltos)

Funciones principales

opcode_to_uop()

FirmaDescripción
pub fn opcode_to_uop(op: &Opcode) -> Uop Convierte un Opcode atómico (no compuesto) a su Uop equivalente. Es el mapeo directo entre bytecode y micro-operaciones. Los opcodes compuestos se mapean a marcadores que luego expandir_a_uops() procesa. Maneja todos los casos: stack, variables, aritmética, control flow, funciones, objetos, arrays, mapas, built-ins, I/O, comparaciones, lógica, opcodes especializados, superinstrucciones, float, AVX2, Exacto, contratos, pattern matching, concurrencia y debug.

expandir_a_uops()

FirmaDescripción
pub fn expandir_a_uops(bytecode: &[Opcode]) -> Vec<Uop> Expande opcodes compuestos en secuencias de uops atómicos (~213 líneas). Descompone superinstrucciones como:
  • DeclareEnteroOp(idx, n)DeclareVar + PushEntero + StorePop
  • LoadIdx2(a, b)LoadIdx(a), LoadIdx(b)
  • LoadStoreIdx(src, dst)LoadIdx(src), StoreIdx(dst)
  • AddStoreIdx(idx)AddInt, StoreIdx(idx)
  • LoadAddInt(idx, n)LoadIdx(idx), PushEntero(n), AddInt
  • PushAddInt(n)PushEntero(n), AddInt
  • LoadJumpSiFalso(idx, target)LoadIdx(idx), JumpSiFalso(target)
  • AVX2 packed: expande a 32 uops escalares (4 iter × 4 uops × 2 pares)
  • XorSign(idx)PushDecimal(0.0), LoadIdx(idx), SubFloat, StoreIdx(idx)
  • Superinstrucciones Exacto (DeclareExactOp, AddStoreExact)

optimizar_uops()

FirmaDescripción
pub fn optimizar_uops(uops: &[Uop]) -> Vec<Uop> Optimiza secuencias de uops fusionando patrones comunes (~63 líneas). Patrones detectados:
  • LoadIdx(a) + PushEntero(1) + Add + StoreIdx(a)IncrVar(a)
  • LoadIdx(a) + PushEntero(n) + Add + StoreIdx(a)AddAssign(a, n)
  • LoadIdx(a) + PushEntero(n) + Sub + StoreIdx(a)SubAssign(a, n)
  • PushEntero(n) + Pop → (eliminar ambos, código muerto)
  • PushBooleano(b) + Pop → (eliminar ambos)
  • PushNulo + Pop → (eliminar ambos)
  • DeclareVar(a) + StorePop(a)DeclareInit(a)

Funciones auxiliares

FirmaDescripción
pub fn tiene_opcodes_compuestos(bytecode: &[Opcode]) -> bool Verifica si un bytecode contiene opcodes compuestos que pueden expandirse a uops. Recorre el bytecode buscando superinstrucciones.
pub fn remapear_saltos_uops(uops: &mut [Uop], bytecode: &[Opcode]) Re-mapea los targets de Jump/Label en uops desde posiciones de bytecode a posiciones de uops, usando el mapeo de expansión.
fn construir_mapeo_posiciones(bytecode: &[Opcode]) -> Vec<usize> Construye un mapeo de posición bytecode → posición uops para re-mapear targets de Jump/Label después de expandir superinstrucciones.

Flujo de generación

  1. El generador de bytecode (bytecode.rs) produce opcodes (algunos compuestos como superinstrucciones)
  2. expandir_a_uops() descompone opcodes compuestos en secuencias de uops atómicos
  3. remapear_saltos_uops() actualiza los targets de saltos a las nuevas posiciones
  4. optimizar_uops() fusiona patrones comunes reduciendo el número de uops
  5. Los uops optimizados se pasan al backend ASM (compiler_asm.rs) o JIT (jit.rs) para emisión de código nativo

Relación con el resto del compilador