RunMat
GitHub

Bytecode Compilation (MIR → Bytecode)

The bytecode compilation stage is the final lowering step before VM execution. It transforms the Mid-Level IR (MIR) into a linear sequence of Instr values, plus the metadata the interpreter needs for variable layout, source spans, semantic function dispatch, async execution, and acceleration planning.

The lowering is managed by the Compiler in runmat-vm. It consumes a MirAssembly and the corresponding HirAssembly, derives a VmAssemblyLayout, emits bytecode for the entry body and semantic functions, patches jumps, and attaches fusion metadata used by the acceleration tiers.

Compiler Architecture

The compiler is a stateful instruction emitter. It tracks the instruction stream, layout, spans, call-argument spans, and deferred jump targets while walking MIR basic blocks.

Key Data Structures

  • Compiler: Orchestrates MIR-to-bytecode lowering.
  • Instr: The VM instruction enum executed by the interpreter.
  • Bytecode: The top-level program container for instructions, layout, functions, spans, async metadata, and fusion metadata.
  • FunctionRegistry: Maps FunctionId and display names to compiled semantic function bytecode.
  • VmAssemblyLayout: Maps MIR locals and HIR bindings to VM slots.

Data Flow: MIR to Bytecode

Loading diagram...

Lowering Responsibilities

MIR Statements and Terminators

The compiler walks each MirBody by basic block. MirStmt values emit stack operations, variable stores, indexing instructions, aggregate constructors, or call instructions. MirTerminator values emit jumps, conditional branches, returns, and exception-region boundaries.

Calls

Call lowering depends on the resolved callee shape:

  • CallBuiltinMulti calls a known runtime built-in.
  • CallSemanticFunctionMulti calls a known function in the compiled semantic assembly.
  • CallFunctionMulti carries a CallableIdentity and CallableFallbackPolicy for runtime resolution.
  • CallFevalMulti keeps the callable value on the stack and resolves it at runtime.
  • *ExpandMultiOutput variants evaluate comma-separated-list expansion before dispatch.

Indexing

The compiler preserves the indexing plan established by MIR. Scalar indexing emits Index or StoreIndex; plain slices emit IndexSlice or StoreSlice; selectors involving runtime end arithmetic emit IndexSliceExpr or StoreSliceExpr.

Control Flow

MIR basic-block targets are not known as final instruction offsets until all relevant blocks are emitted. The compiler therefore records block-to-instruction mappings and patches Jump, JumpIfFalse, AndAnd, and OrOr targets after emission.

Complete Instruction Set

The table below lists every current Instr variant, grouped by runtime behavior.

Constants, Variables, and Locals

InstructionsPurpose
LoadConst, LoadComplex, LoadBool, LoadString, LoadCharRowPush literal values onto the stack.
LoadVar, LoadVarForIndexAssignment, StoreVarRead and write workspace variable slots. LoadVarForIndexAssignment can initialize an undefined indexed-assignment base.
EnterScope, ExitScope, LoadLocal, StoreLocalManage local frame storage and local slot access.

Arithmetic, Comparison, and Logical Operations

InstructionsPurpose
Add, Sub, Mul, RightDiv, LeftDiv, PowMatrix/scalar arithmetic operations.
Neg, UPlusUnary arithmetic operations.
Transpose, ConjugateTransposeMATLAB transpose operators.
ElemMul, ElemDiv, ElemPow, ElemLeftDivElement-wise arithmetic operations.
LessEqual, Less, Greater, GreaterEqual, Equal, NotEqualComparison operations.
LogicalNot, LogicalAnd, LogicalOrEager logical operations.
AndAnd, OrOrShort-circuit logical control-flow operations.

Stack and Control Flow

InstructionsPurpose
Pop, Swap, UnpackStack manipulation and output-list expansion.
JumpIfFalse, JumpBranch to patched instruction offsets.
EnterTry, PopTryMaintain the try/catch handler stack.
Return, ReturnValueExit the current interpreter frame.
StochasticEvolutionSpecialized fast-path marker for stochastic evolution kernels.

Array and Aggregate Construction

InstructionsPurpose
CreateMatrix, CreateMatrixDynamicBuild matrix values from stack operands.
CreateRangeBuild colon/range values.
CreateCell2DBuild cell arrays.
CreateStructLiteralBuild struct literals from named field values.
CreateObjectLiteralBuild object literals with class names and field values.
PackToRow, PackToColPack stack values into row or column tensor form.

Indexing and Assignment

InstructionsPurpose
Index, StoreIndex, StoreIndexDeleteScalar or linear paren indexing and assignment.
IndexSlice, StoreSlice, StoreSliceDeleteSlice indexing with compiler-encoded colon and plain end masks.
IndexSliceExpr, StoreSliceExpr, StoreSliceExprDeleteGeneral slice indexing with dynamic ranges and EndExpr arithmetic.
IndexCell, IndexCellExpand, IndexCellListBrace/cell indexing, fixed-arity expansion, and first-class comma-separated-list creation.
StoreIndexCell, StoreIndexCellDeleteBrace/cell indexed assignment and deletion form.

Indexed assignment instructions push the updated base value. A later StoreVar or StoreLocal commits that updated base to its destination slot.

Struct, Object, Class, and Member Operations

InstructionsPurpose
LoadMember, LoadMemberOrInit, LoadMemberDynamic, LoadMemberDynamicOrInitRead static or dynamic members, with optional initialization semantics.
StoreMember, StoreMemberOrInit, StoreMemberDynamic, StoreMemberDynamicOrInitWrite static or dynamic members, with optional initialization semantics.
LoadMethodLoad a method reference from an object-like value.
CallMethodOrMemberIndexMulti, CallMethodOrMemberIndexExpandMultiOutputResolve ambiguous method/member indexing calls at runtime.
LoadStaticPropertyLoad a class static property.
RegisterClassRegister a lowered classdef definition at runtime.

Function Handles, Calls, and Async

InstructionsPurpose
CreateFunctionHandle, CreateExternalFunctionHandle, CreateMethodFunctionHandle, CreateBoundFunctionHandleBuild function-handle values.
CreateClosure, CreateSemanticClosureBuild closure values with captured stack operands.
CallBuiltinMulti, CallBuiltinExpandMultiOutputDispatch runtime built-ins.
CallFunctionMulti, CallFunctionExpandMultiOutputDispatch a CallableIdentity through fallback-aware callable resolution.
CallSemanticFunctionMulti, CallSemanticFunctionExpandMultiOutputDispatch directly to compiled semantic functions.
CallFevalMulti, CallFevalExpandMultiOutputDispatch a runtime callable value through feval.
CreateSemanticFuture, CreateSemanticFutureExpandMultiOutputBuild lazy semantic-future descriptors.
Spawn, AwaitExplicit async spawn and await boundaries.

Imports, Globals, Persistents, and Visible Output

InstructionsPurpose
RegisterImportRegister an import path for later unqualified callable resolution.
DeclareGlobal, DeclareGlobalNamedDeclare global slots, including name-stable forms across units.
DeclarePersistent, DeclarePersistentNamedDeclare persistent slots, including name-stable forms across units.
EmitStackTop, EmitVarEmit visible workspace output labels such as ans or a variable name.

Supporting Operand Types

EndExpr

EndExpr represents selector expressions that depend on the runtime size of the indexed value. It supports:

  • Base values: End, Const, Var.
  • Callable expressions: ResolvedCall.
  • Arithmetic: Add, Sub, Mul, Div, LeftDiv, Pow.
  • Unary and rounding operations: Neg, Pos, Floor, Ceil, Round, Fix.

ArgSpec

ArgSpec describes multi-output argument expansion for call instructions. It records whether an argument is expanded, how many indices are consumed for a brace/object expansion, and whether the expansion consumes all contents.

Stack Effects

Most instructions have a static StackEffect reported by Instr::stack_effect(). The effect is used by metadata and acceleration planning:

  • Literal loads, variable loads, function-handle creation, and local loads push one value.
  • Binary arithmetic and comparisons pop two values and push one.
  • Calls pop their arguments and push the requested result shape.
  • Indexed writes pop the base, selectors, and RHS, then push the updated base.
  • StochasticEvolution has no ordinary static stack effect because it is handled as a specialized fast path.

IndexSliceExpr and the expanded call variants also carry structured operand metadata. Their exact runtime pops depend on the encoded range or expansion specs, while the bytecode still records enough static information for planning and validation.

System Entity Mapping

Loading diagram...

Acceleration and Fusion Metadata

The compiler generates FusionMetadata to assist the GPU offload engine and runtime planner.

Metadata EntityPurpose
FusionCandidateGroupsIdentifies sequences of MIR operations that are valid candidates for fusion.
InstructionWindowsMaps emitted instruction ranges back to fusion candidates.
AccelGraphDescribes bytecode data flow for residency planning and CPU/GPU transfer minimization.

Error Handling and Validation

The compiler validates MIR and HIR contracts before emitting bytecode. Stable error identifiers include:

  • RunMat:MirScalarIndexPlanInvalid: A scalar indexing plan cannot be lowered safely.
  • RunMat:MirSliceIndexPlanInvalid: A slice or end-relative plan is malformed.
  • RunMat:MirCellIndexPlanInvalid: A cell indexing plan is malformed.
  • RunMat:MirFunctionHandleNameMissing: A function handle target lacks a usable name.
  • RunMat:ImportAmbiguous: Import resolution produced conflicting candidates.

From here, bytecode execution continues in Interpreter Dispatch & Execution Loop.