vcode

    Target-independent native lowering, VCode, and code-object infrastructure

    compiler
    vcode
    register-allocation
    codegen
    Download zip
    Author
    Version
    0.14.0
    License
    Apache-2.0
    Last updated
    13 days ago
    Downloads
    42

    #vcode

    Milky2018/vcode provides the target-independent infrastructure shared by Wasmoon's native backends. It defines the semantic vocabulary at the native compiler boundary, a streaming instruction-selection protocol, dense storage for target-owned VCode, allocation side tables and verifiers, parallel-move planning, and verified unlinked code objects.

    The module is intended for compiler backends and embedding runtimes. It is not a source-language IR, an optimizer, a register allocator, or an executable-code loader. MilkIR owns target-independent program structure and optimization; Milky2018/regalloc owns allocation policy; each target owns its instructions, ABI, frame layout, and encoding; the embedding product owns symbol resolution, executable memory, and runtime registration.

    #Packages

    PackageResponsibility
    Milky2018/vcode/native_typesCanonical native value types, signatures, calls, symbols, operation effects, traps, safepoints, source locations, and stack-map metadata.
    Milky2018/vcode/native_loweringStreaming producer-to-target protocol, target-neutral operations, transient value and block handles, and call-ABI elaboration.
    Milky2018/vcode/allocation_typesMinimal register-allocation vocabulary shared by VCode, the allocator, and their adapter: register classes, physical and virtual registers, operand roles and timing, constraints, and compact locations.
    Milky2018/vcodeDense target VCode, checked construction, allocation and frame side tables, staged verification, call-transfer planning, and parallel-move resolution.
    Milky2018/vcode/code_objectVerified machine-code bytes with typed relocations, source and trap sites, safepoints and roots, and target-neutral unwind directives.

    These packages are separate ownership seams inside one module, not successive copies of the same IR. In particular, native_lowering does not depend on the VCode package and does not retain a function graph. A target implements a TargetSink that translates each streamed operation directly into its own instruction type stored by vcode.

    #Compiler flow

    MilkIR and dialect adapters | | native_lowering.Operation, one operation at a time v target TargetSink --> target-owned Inst in vcode.Function[Inst] | | verify_selected v regalloc + vcode allocation side tables | | verify_allocated v target frame layout | | verify_framed / verify_emission_input v target machine-code emitter | v code_object.UnlinkedCodeObject | v embedding-owned linker and code loader

    native_types supplies the common vocabulary on both sides of the lowering seam. allocation_types supplies identities that must be shared exactly by VCode and Milky2018/regalloc; targets should not introduce parallel register class, operand-role, or allocation-location types.

    #Constructing target VCode

    The instruction payload is generic. A target defines an instruction type, then uses CheckedBuilder[Inst] to attach operands, constraints, clobbers, CFG edges, and metadata. Handles are function-owned, so values, blocks, and instructions from different functions cannot be mixed accidentally.

    ///|
    priv enum ExampleInst {
    AddOne
    Return
    } derive(Debug)

    ///|
    test "construct and verify target VCode" {
    let builder : CheckedBuilder[ExampleInst] = CheckedBuilder::new_with_results(
    "add_one",
    [I64],
    [I64],
    )
    let entry = builder.entry_block()
    let input = builder.parameter(0)
    let (_, results) = builder.append_body(
    entry,
    AddOne,
    [Input::any(input)],
    [Output::any(I64)],
    [],
    InstructionMetadata::empty(),
    )
    builder.set_terminator(
    entry,
    Return,
    [Input::any(results[0])],
    [],
    [],
    InstructionMetadata::empty(),
    )
    |> ignore

    let function = builder.finish()
    verify_selected(function)
    inspect(function.parameter_count(), content="1")
    inspect(function.instruction_count(), content="2")
    inspect(function.summary().contains("AddOne"), content="true")
    }

    CheckedBuilder is the normal production construction API: it rejects invalid operands and edges before mutation and checks local completeness when it is sealed. It does not replace verify_selected, which checks whole-function CFG and SSA properties. The lower-level Builder is useful for negative tests and tooling that deliberately needs to construct an invalid intermediate state.

    An Input or Output describes a correctness constraint independently from a placement preference. Fixed and TiedTo are hard constraints. A preferred physical register is only a hint and must not make an otherwise legal allocation fail. Early and Late operand timing lets the allocator model when an instruction stops using an input and starts defining an output.

    #Streaming native lowering

    Milky2018/vcode/native_lowering is the boundary between a legalized MilkIR producer and a native target. DirectBuilder exposes typed, transient Value and Block handles to the producer and forwards operations to a TargetSink. It retains only the bookkeeping needed to track types, map transient handles to target ids, delay one terminator, and elaborate configured call ABI details. It does not retain instructions, uses, SSA definitions, or CFG edges.

    The protocol defines operation semantics, while the producer owns source-level legalization. The target owns instruction selection, target immediates, calling-convention decisions, physical-register policy, and target VCode verification. Call-ABI elaboration may add hidden stack-map arguments or caller root scopes, but only when an embedding explicitly supplies the corresponding contract.

    Use Milky2018/milkir/native to stream core MilkIR and Milky2018/wasm_milkir/native for the WebAssembly dialect. Target users normally create an AArch64 or x64 lowering session instead of constructing a TargetSink directly.

    #Allocation and move planning

    Function[Inst] is the authoritative selected machine graph. Allocation is stored separately in Allocation, so register assignment, spills, reloads, edge transfers, safepoint roots, and frame placement do not rewrite or clone the instruction graph. Milky2018/vcode_regalloc exposes the function through the allocator's read-only view and materializes its returned plan into these side tables.

    Parallel assignments are planned with a dedicated transfer scratch for each register bank. When a cycle and a stack-to-stack transfer cannot be resolved safely with that scratch, the planner emits explicit emergency save and restore steps. The target owns the physical emergency area and must verify that its frame reserves it whenever the resolved plan requires it.

    The verification functions represent lifecycle boundaries:

    • verify_selected checks CFG shape, SSA dominance, operands, clobbers, metadata, and layout before allocation.
    • verify_allocated checks homes, operand locations, edits, interference, clobbers, and safepoint roots after allocation.
    • verify_framed adds spill-slot placement, alignment, overlap, and frame-size checks.
    • verify_emission_input is the final target-independent gate immediately before encoding.

    Verification validates the current snapshot; it does not permanently mark a mutable function or side table as verified. Run the appropriate verifier again after any later mutation.

    #Unlinked code objects

    Milky2018/vcode/code_object.build is the final reusable boundary between a target emitter and an embedding runtime. It copies the machine-code bytes and metadata, validates them, and returns an UnlinkedCodeObject only when all architecture, alignment, bounds, relocation, instruction-encoding, stack-map, root-location, and unwind-state contracts hold.

    ///|
    let object = @code_object.build(@code_object.X64, [b'\xc3'])

    Relocations remain symbolic. The package does not resolve runtime symbols, apply relocations, allocate executable memory, encode platform unwind formats, or register unwind data with the host. Those responsibilities belong to the embedding runtime. An unwind directive's offset is the code offset immediately after the prologue instruction that establishes the described state; saved register locations are relative to the canonical frame address.

    #Integration guidance

    • Import the narrowest package that owns the contract you need. A frontend usually needs native_types and native_lowering; a target also needs the root package and code_object; a loader normally needs only native_types and code_object.
    • Keep target-specific instruction variants and ABI policy in the target module. The generic packages should never depend on AArch64, x64, or Wasmoon runtime layouts.
    • Keep runtime symbol resolution and executable-code installation outside this module. Code objects are ordinary verified data until an embedding installs them.
    • Treat verification errors as compiler contract failures with structured diagnostics. Do not bypass a failed stage to continue emission.

    AllocationConstraint

    A normalized register-allocation constraint.

    Operand ties are represented separately by a shared nonnegative tie label, so this type contains only location constraints.

    AllocationLocation

    A packed allocation result location within one allocation session.

    Spill indices are session-local and must be translated at ownership boundaries before they are exposed as product-facing stack-slot handles.

    AllocationOperand

    The canonical allocation facts for one instruction operand.

    AllocationVirtualReg

    using @Milky2018/vcode/allocation_types { type VirtualReg as AllocationVirtualReg }

    A dense virtual-register identity within one allocation session.

    OperandRole

    Whether an allocation operand reads, writes, or both reads and writes its virtual register.

    SSA VCode producers use Use and Def. UseDef remains available to standalone register-allocation clients that model in-place updates.

    OperandTiming

    The point within an instruction where an allocation operand is read or written.

    PhysicalReg

    A target physical register identified within one register class.

    RegClass

    Target-neutral register-class identity shared by VCode and register allocation.

    FpVector preserves targets whose scalar floating-point and vector values occupy one physical register bank. Float and Vector remain available to standalone allocator embeddings that model distinct banks.

    ValueType

    Exact target-neutral value types shared by native lowering and target VCode.

    Ptr64 is an untraced address or opaque handle. GcRef64 is a nullable managed reference and must be reported as a root at GC safepoints.

    AllocationVerifyError

    pub suberror AllocationVerifyError {
    SelectedFailure(cause~ : VCodeVerifyError)
    SourceMismatch
    MissingValueLocation(value~ : Value)
    ForeignLocation(value~ : Value)
    LocationClassMismatch(value~ : Value)
    MissingOperandLocation(instruction~ : Instruction, operand~ : Int)
    OperandClassMismatch(instruction~ : Instruction, operand~ : Int)
    RegisterConstraintViolation(instruction~ : Instruction, operand~ : Int)
    FixedConstraintViolation(instruction~ : Instruction, operand~ : Int)
    PreservedHomeConstraintViolation(instruction~ : Instruction, operand~ : Int)
    TiedConstraintViolation(instruction~ : Instruction, operand~ : Int)
    Interference(left~ : Value, right~ : Value, location~ : Location)
    ClobberViolation(instruction~ : Instruction, value~ : Value)
    InvalidStackSlotLayout(slot~ : StackSlot)
    InvalidEdit(index~ : Int)
    MissingReload(instruction~ : Instruction, operand~ : Int)
    InvalidEdgeMove(index~ : Int)
    MissingSafepointRoot(instruction~ : Instruction, value~ : Value)
    UnexpectedSafepointRoot(instruction~ : Instruction, value~ : Value)
    } derive(Eq,
    Debug
    )

    AllocationVerifyError::equal

    AllocationVerifyError::not_equal

    AllocationVerifyError::output

    fn AllocationVerifyError::output(self : AllocationVerifyError, logger : &Logger) -> Unit

    AllocationVerifyError::to_string

    fn AllocationVerifyError::to_string(self : AllocationVerifyError) -> String

    CallTransferError

    pub suberror CallTransferError {
    InvalidSourceClass(index~ : Int)
    ForeignSourceStack(index~ : Int)
    InvalidSourceStackType(index~ : Int, expected~ :
    ValueType
    , actual~ :
    ValueType
    )
    InvalidSourceStackLayout(index~ : Int)
    InvalidDestinationClass(index~ : Int)
    InvalidStackOffset(index~ : Int, offset~ : Int)
    InvalidOutgoingStackRange(start~ : Int, size~ : Int)
    OutgoingStackDestinationOutOfRange(index~ : Int, offset~ : Int)
    DuplicateRegisterDestination(index~ : Int, register~ :
    PhysicalReg
    )
    OverlappingStackDestination(first~ : Int, second~ : Int)
    ProtectedLocationOverwrite(index~ : Int, location~ : Location)
    MoveResolutionFailed(cause~ : MoveResolveError)
    } derive(Eq,
    Debug
    )

    CallTransferError::equal

    CallTransferError::not_equal

    fn CallTransferError::not_equal(x : CallTransferError, y : CallTransferError) -> Bool

    EmissionVerifyError

    pub suberror EmissionVerifyError {
    FrameFailure(cause~ : FrameVerifyError)
    } derive(Eq,
    Debug
    )

    EmissionVerifyError::equal

    EmissionVerifyError::not_equal

    EmissionVerifyError::output

    fn EmissionVerifyError::output(self : EmissionVerifyError, logger : &Logger) -> Unit

    EmissionVerifyError::to_string

    fn EmissionVerifyError::to_string(self : EmissionVerifyError) -> String

    FrameVerifyError

    pub suberror FrameVerifyError {
    AllocationFailure(cause~ : AllocationVerifyError)
    SourceMismatch
    InvalidFrameSize(size~ : Int)
    InvalidFrameAlignment(alignment~ : Int)
    MissingStackSlot(slot~ : StackSlot)
    MisalignedStackSlot(slot~ : StackSlot)
    OverlappingStackSlots(left~ : StackSlot, right~ : StackSlot)
    StackSlotOutOfFrame(slot~ : StackSlot)
    } derive(Eq,
    Debug
    )

    FrameVerifyError::equal

    FrameVerifyError::not_equal

    fn FrameVerifyError::not_equal(x : FrameVerifyError, y : FrameVerifyError) -> Bool

    FrameVerifyError::output

    fn FrameVerifyError::output(self : FrameVerifyError, logger : &Logger) -> Unit

    FrameVerifyError::to_string

    fn FrameVerifyError::to_string(self : FrameVerifyError) -> String

    MoveResolveError

    MoveResolveError::equal

    MoveResolveError::not_equal

    fn MoveResolveError::not_equal(x : MoveResolveError, y : MoveResolveError) -> Bool

    MoveResolveError::output

    fn MoveResolveError::output(self : MoveResolveError, logger : &Logger) -> Unit

    MoveResolveError::to_string

    fn MoveResolveError::to_string(self : MoveResolveError) -> String

    VCodeBuildError

    pub suberror VCodeBuildError {
    InvalidParameter(index~ : Int)
    InvalidBlockParameter(block~ : Block, index~ : Int)
    ForeignBlock(block~ : Block)
    ForeignValue(value~ : Value)
    InvalidOperandConstraint
    DuplicateTerminator(block~ : Block)
    BlockAlreadyTerminated(block~ : Block)
    InvalidEdgeArity(block~ : Block)
    EdgeClassMismatch(block~ : Block, index~ : Int)
    DuplicateClobber(reg~ :
    PhysicalReg
    )
    InvalidSafepointRoot(value~ : Value)
    InvalidStackMap
    MissingTerminator(block~ : Block)
    InvalidLayout
    } derive(Eq,
    Debug
    )

    VCodeBuildError::equal

    VCodeBuildError::not_equal

    fn VCodeBuildError::not_equal(x : VCodeBuildError, y : VCodeBuildError) -> Bool

    VCodeBuildError::output

    fn VCodeBuildError::output(self : VCodeBuildError, logger : &Logger) -> Unit

    VCodeBuildError::to_string

    fn VCodeBuildError::to_string(self : VCodeBuildError) -> String

    VCodeVerifyError

    pub suberror VCodeVerifyError {
    EmptyFunction
    MissingTerminator(block~ : Block)
    ForeignValue(instruction~ : Instruction, value~ : Value)
    ForeignBlock(instruction~ : Instruction, block~ : Block)
    InvalidEdgeArity(instruction~ : Instruction, block~ : Block)
    EdgeClassMismatch(instruction~ : Instruction, block~ : Block, index~ : Int)
    InvalidTie(instruction~ : Instruction, operand~ : Int, tied_to~ : Int)
    FixedRegisterClassMismatch(instruction~ : Instruction, operand~ : Int)
    InvalidOperandPreference(instruction~ : Instruction, operand~ : Int)
    DuplicateClobber(instruction~ : Instruction, reg~ :
    PhysicalReg
    )
    InvalidSafepointRoot(instruction~ : Instruction, value~ : Value)
    InvalidStackMap(instruction~ : Instruction)
    UnreachableBlock(block~ : Block)
    UseBeforeDefinition(instruction~ : Instruction, value~ : Value)
    DefinitionDoesNotDominate(instruction~ : Instruction, value~ : Value)
    InvalidLayout
    } derive(Eq,
    Debug
    )

    VCodeVerifyError::equal

    VCodeVerifyError::not_equal

    fn VCodeVerifyError::not_equal(x : VCodeVerifyError, y : VCodeVerifyError) -> Bool

    VCodeVerifyError::output

    fn VCodeVerifyError::output(self : VCodeVerifyError, logger : &Logger) -> Unit

    VCodeVerifyError::to_string

    fn VCodeVerifyError::to_string(self : VCodeVerifyError) -> String

    Allocation

    pub struct Allocation {
    // private fields
    }

    Allocation::add_edit

    fn Allocation::add_edit(self : Allocation, edit : Edit) -> Bool

    Allocation::add_safepoint_root

    fn Allocation::add_safepoint_root(self : Allocation, instruction : Instruction, value : Value, location : Location) -> Bool

    Allocation::allocated_operand_location_at

    fn Allocation::allocated_operand_location_at(self : Allocation, instruction : Int, operand : Int) ->
    AllocationLocation
    ?

    Return a canonical allocation location by dense instruction and operand indices. Spill indices belong to this allocation.

    Allocation::allocated_value_location_at

    Return a canonical allocation location by dense value index.

    Spill indices belong to this allocation and must not be used as public stack-slot handles. Compiler infrastructure that needs such a handle must call stack_slot_at on the same allocation.

    Allocation::assign_operand

    fn Allocation::assign_operand(self : Allocation, instruction : Instruction, operand_index : Int, reg :
    PhysicalReg
    ) -> Bool

    Allocation::assign_operand_location

    fn Allocation::assign_operand_location(self : Allocation, instruction : Instruction, operand_index : Int, location : Location) -> Bool

    Allocation::assign_value

    fn Allocation::assign_value(self : Allocation, value : Value, location : Location) -> Bool

    Allocation::create_stack_slot

    fn Allocation::create_stack_slot(self : Allocation, ty :
    ValueType
    , size : Int, alignment : Int) -> StackSlot

    Allocation::edge_edits_at

    fn Allocation::edge_edits_at(self : Allocation, source : Block, successor_index : Int) -> ArrayView[Edit]

    Returns the allocation edits scheduled for one outgoing CFG edge.

    The returned view is read-only and remains valid while this allocation is not mutated. Target emitters should query this index instead of scanning edits() for every edge.

    Allocation::edit_count

    fn Allocation::edit_count(self : Allocation) -> Int

    Allocation::edits

    fn Allocation::edits(self : Allocation) -> Array[Edit]

    Allocation::edits_at

    fn Allocation::edits_at(self : Allocation, instruction : Instruction, placement : PointPlacement) -> ArrayView[Edit]

    Returns the allocation edits scheduled at one instruction point.

    The returned view is read-only and remains valid while this allocation is not mutated. Target emitters should query this index instead of scanning edits() for every instruction.

    Allocation::for_function

    fn[Inst] Allocation::for_function(function : Function[Inst]) -> Allocation

    Allocation::operand_location

    fn Allocation::operand_location(self : Allocation, instruction : Instruction, operand_index : Int) -> Location?

    Allocation::safepoint_roots

    fn Allocation::safepoint_roots(self : Allocation, instruction : Instruction) -> Array[(Value, Location)]

    Allocation::source_instruction_count

    fn Allocation::source_instruction_count(self : Allocation) -> Int

    Allocation::stack_slot_alignment

    fn Allocation::stack_slot_alignment(self : Allocation, slot : StackSlot) -> Int?

    Allocation::stack_slot_at

    fn Allocation::stack_slot_at(self : Allocation, index : Int) -> StackSlot?

    Allocation::stack_slot_count

    fn Allocation::stack_slot_count(self : Allocation) -> Int

    Allocation::stack_slot_size

    fn Allocation::stack_slot_size(self : Allocation, slot : StackSlot) -> Int?

    Allocation::stack_slot_type

    Allocation::statistics

    fn Allocation::statistics(self : Allocation) -> AllocationStatistics

    Allocation::summary

    fn Allocation::summary(self : Allocation) -> String

    Allocation::value_location

    fn Allocation::value_location(self : Allocation, value : Value) -> Location?

    Return the value's default transfer home.

    A verified segmented allocation may keep the newest value in an instruction- or edge-specific location until an edit returns it here.

    AllocationBuilder

    pub struct AllocationBuilder[Inst] {
    // private fields
    }

    Dense-index writer used after a verified register-allocation plan has been produced for this exact function.

    The writer avoids reconstructing and revalidating owner-tagged handles for every value, operand, and edit. Indices must come from the matching function and stay within its published counts. Final allocation invariants remain the authoritative validation boundary.

    AllocationBuilder::add_edge_transfer

    fn[Inst] AllocationBuilder::add_edge_transfer(self : AllocationBuilder[Inst], source_block : Int, successor : Int, value : Int, from :
    AllocationLocation
    , to :
    AllocationLocation
    ) -> Bool

    AllocationBuilder::add_function_safepoint_roots

    fn[Inst] AllocationBuilder::add_function_safepoint_roots(self : AllocationBuilder[Inst]) -> Bool

    Adds every selected VCode safepoint root through dense internal ids.

    Selected-function validation already established metadata ownership and root types; this method retains allocation-location checks without copying layouts, instruction metadata, or owner-tagged root snapshots.

    AllocationBuilder::add_safepoint_root

    fn[Inst] AllocationBuilder::add_safepoint_root(self : AllocationBuilder[Inst], instruction : Int, value : Int) -> Bool

    AllocationBuilder::add_transfer

    AllocationBuilder::assign_operand

    fn[Inst] AllocationBuilder::assign_operand(self : AllocationBuilder[Inst], instruction : Int, operand : Int, location :
    AllocationLocation
    ) -> Bool

    AllocationBuilder::assign_value

    fn[Inst] AllocationBuilder::assign_value(self : AllocationBuilder[Inst], value : Int, location :
    AllocationLocation
    ) -> Bool

    AllocationBuilder::create_stack_slot

    fn[Inst] AllocationBuilder::create_stack_slot(self : AllocationBuilder[Inst], value : Int, size : Int, alignment : Int) -> Int

    AllocationBuilder::finish

    fn[Inst] AllocationBuilder::finish(self : AllocationBuilder[Inst]) -> Allocation

    AllocationBuilder::from_plan_storage

    fn[Inst] AllocationBuilder::from_plan_storage(function : Function[Inst], value_locations : Array[
    AllocationLocation
    ?], operand_locations : Array[Array[
    AllocationLocation
    ?]], spill_owners : Array[Int], spill_sizes : Array[Int], spill_alignments : Array[Int]) -> AllocationBuilder[Inst]?

    Adopts canonical location tables produced for this exact selected function.

    The caller must stop mutating the source tables after adoption. Shape, location class, spill ownership, size, and alignment are checked here so callers that disable the final allocation verifier retain the same local construction guarantees as incremental builder writes.

    AllocationBuilder::new

    fn[Inst] AllocationBuilder::new(function : Function[Inst]) -> AllocationBuilder[Inst]

    AllocationBuilder::operand_value_at

    fn[Inst] AllocationBuilder::operand_value_at(self : AllocationBuilder[Inst], instruction : Int, operand : Int) -> Int

    AllocationBuilder::value_location

    AllocationBuilder::value_type_at

    fn[Inst] AllocationBuilder::value_type_at(self : AllocationBuilder[Inst], value : Int) ->
    ValueType

    AllocationStatistics

    pub struct AllocationStatistics {
    spill_slots : Int
    spills : Int
    reloads : Int
    reg_moves : Int
    spill_to_spill : Int
    } derive(Eq,
    Debug
    )

    Read-only summary of the transfers introduced by register allocation.

    AllocationStatistics::equal

    AllocationStatistics::not_equal

    Block

    pub struct Block {
    // private fields
    }

    impl Eq for Block
    impl Show for Block

    Block::equal

    fn Block::equal(self : Block, other : Block) -> Bool

    Block::not_equal

    fn Block::not_equal(x : Block, y : Block) -> Bool

    Block::output

    fn Block::output(self : Block, logger : &Logger) -> Unit

    Block::to_repr

    Block::to_string

    fn Block::to_string(self : Block) -> String

    Builder

    pub struct Builder[Inst] {
    // private fields
    }

    Builder::append_body

    fn[Inst] Builder::append_body(self : Builder[Inst], block : Block, inst : Inst, inputs : Array[Input], outputs : Array[Output], clobbers : Array[
    PhysicalReg
    ], metadata : InstructionMetadata) -> (Instruction, Array[Value]) raise VCodeBuildError

    Builder::block_parameter

    fn[Inst] Builder::block_parameter(self : Builder[Inst], block : Block, index : Int) -> Value raise VCodeBuildError

    Builder::create_block

    fn[Inst] Builder::create_block(self : Builder[Inst], parameter_types : Array[
    ValueType
    ]) -> Block

    Builder::entry_block

    fn[Inst] Builder::entry_block(self : Builder[Inst]) -> Block

    Builder::finish

    fn[Inst] Builder::finish(self : Builder[Inst]) -> Function[Inst]

    Builder::new

    fn[Inst] Builder::new(name : String, parameter_types : Array[
    ValueType
    ]) -> Builder[Inst]

    Builder::new_with_protocol

    Builder::new_with_results

    fn[Inst] Builder::new_with_results(name : String, parameter_types : Array[
    ValueType
    ], result_types : Array[
    ValueType
    ]) -> Builder[Inst]

    Builder::parameter

    fn[Inst] Builder::parameter(self : Builder[Inst], index : Int) -> Value raise VCodeBuildError

    Builder::set_terminator

    fn[Inst] Builder::set_terminator(self : Builder[Inst], block : Block, inst : Inst, inputs : Array[Input], successors : Array[Edge], clobbers : Array[
    PhysicalReg
    ], metadata : InstructionMetadata) -> Instruction raise VCodeBuildError

    CallTransfer

    pub struct CallTransfer {
    // private fields
    }

    One allocated source and its physical destination in a target call layout.

    CallTransfer::to_stack

    CallTransferPlan

    pub struct CallTransferPlan {
    stack_transfers : Array[StackArgumentTransfer]
    register_moves : Array[ParallelMove]
    } derive(Eq,
    Debug
    )

    CallTransferPlan::equal

    CallTransferPlan::not_equal

    fn CallTransferPlan::not_equal(x : CallTransferPlan, y : CallTransferPlan) -> Bool

    CheckedBuilder

    pub struct CheckedBuilder[Inst] {
    // private fields
    }

    A production builder that establishes local VCode invariants before every mutation. The permissive Builder remains available for external tools and verifier negative tests; target selectors use this type so sealing does not need to rediscover local facts by scanning the completed instruction list.

    CheckedBuilder::append_body

    fn[Inst] CheckedBuilder::append_body(self : CheckedBuilder[Inst], block : Block, inst : Inst, inputs : Array[Input], outputs : Array[Output], clobbers : Array[
    PhysicalReg
    ], metadata : InstructionMetadata) -> (Instruction, Array[Value]) raise VCodeBuildError

    CheckedBuilder::block_parameter

    fn[Inst] CheckedBuilder::block_parameter(self : CheckedBuilder[Inst], block : Block, index : Int) -> Value raise VCodeBuildError

    CheckedBuilder::create_block

    fn[Inst] CheckedBuilder::create_block(self : CheckedBuilder[Inst], parameter_types : Array[
    ValueType
    ]) -> Block

    CheckedBuilder::entry_block

    fn[Inst] CheckedBuilder::entry_block(self : CheckedBuilder[Inst]) -> Block

    CheckedBuilder::finish

    fn[Inst] CheckedBuilder::finish(self : CheckedBuilder[Inst]) -> Function[Inst] raise VCodeBuildError

    CheckedBuilder::new

    fn[Inst] CheckedBuilder::new(name : String, parameter_types : Array[
    ValueType
    ]) -> CheckedBuilder[Inst]

    CheckedBuilder::new_with_protocol

    CheckedBuilder::new_with_results

    fn[Inst] CheckedBuilder::new_with_results(name : String, parameter_types : Array[
    ValueType
    ], result_types : Array[
    ValueType
    ]) -> CheckedBuilder[Inst]

    CheckedBuilder::parameter

    fn[Inst] CheckedBuilder::parameter(self : CheckedBuilder[Inst], index : Int) -> Value raise VCodeBuildError

    CheckedBuilder::set_terminator

    fn[Inst] CheckedBuilder::set_terminator(self : CheckedBuilder[Inst], block : Block, inst : Inst, inputs : Array[Input], successors : Array[Edge], clobbers : Array[
    PhysicalReg
    ], metadata : InstructionMetadata) -> Instruction raise VCodeBuildError

    Edge

    pub struct Edge {
    target : Block
    arguments : Array[Value]
    }

    Edge::new

    fn Edge::new(target : Block, arguments : Array[Value]) -> Edge

    Edit

    pub struct Edit {
    point : ProgramPoint?
    kind : EditKind
    }

    Edit::edge_move

    fn Edit::edge_move(source : Block, successor_index : Int, value : Value, from : Location, to : Location) -> Edit

    Edit::kind

    fn Edit::kind(self : Edit) -> EditKind

    Edit::point

    fn Edit::point(self : Edit) -> ProgramPoint?

    Edit::reload

    EditKind

    pub(all) enum EditKind {
    Spill(value~ : Value, reg~ :
    PhysicalReg
    , slot~ : StackSlot)
    Reload(value~ : Value, slot~ : StackSlot, reg~ :
    PhysicalReg
    )
    Move(value~ : Value, from~ :
    PhysicalReg
    , to~ :
    PhysicalReg
    )
    EdgeMove(source~ : Block, successor_index~ : Int, value~ : Value, from~ : Location, to~ : Location)
    } derive(Eq,
    Debug
    )

    EditKind::equal

    fn EditKind::equal(EditKind, EditKind) -> Bool

    EditKind::not_equal

    fn EditKind::not_equal(x : EditKind, y : EditKind) -> Bool

    EditKind::to_repr

    FrameLayout

    pub struct FrameLayout {
    // private fields
    }

    FrameLayout::alignment

    fn FrameLayout::alignment(self : FrameLayout) -> Int

    FrameLayout::frame_size

    fn FrameLayout::frame_size(self : FrameLayout) -> Int

    FrameLayout::new

    fn[Inst] FrameLayout::new(function : Function[Inst], allocation : Allocation, frame_size : Int, alignment : Int) -> FrameLayout

    FrameLayout::place_slot

    fn FrameLayout::place_slot(self : FrameLayout, slot : StackSlot, offset : Int) -> Bool

    FrameLayout::slot_offset

    fn FrameLayout::slot_offset(self : FrameLayout, slot : StackSlot) -> Int?

    Function

    pub struct Function[Inst] {
    // private fields
    }

    Function::after

    fn[Inst] Function::after(self : Function[Inst], instruction : Instruction) -> ProgramPoint?

    Function::allocation_block_instruction_at

    fn[Inst] Function::allocation_block_instruction_at(self : Function[Inst], block : Int, instruction : Int) -> Int

    Function::allocation_block_instruction_count

    fn[Inst] Function::allocation_block_instruction_count(self : Function[Inst], block : Int) -> Int

    Function::allocation_block_parameter_at

    fn[Inst] Function::allocation_block_parameter_at(self : Function[Inst], block : Int, parameter : Int) ->
    VirtualReg

    Function::allocation_block_parameter_count

    fn[Inst] Function::allocation_block_parameter_count(self : Function[Inst], block : Int) -> Int

    Function::allocation_block_successor_at

    fn[Inst] Function::allocation_block_successor_at(self : Function[Inst], block : Int, successor : Int) -> Int

    Function::allocation_block_successor_count

    fn[Inst] Function::allocation_block_successor_count(self : Function[Inst], block : Int) -> Int

    Function::allocation_edge_argument_at

    fn[Inst] Function::allocation_edge_argument_at(self : Function[Inst], block : Int, successor : Int, argument : Int) ->
    VirtualReg

    Function::allocation_edge_argument_count

    fn[Inst] Function::allocation_edge_argument_count(self : Function[Inst], block : Int, successor : Int) -> Int

    Function::allocation_entry_value_at

    fn[Inst] Function::allocation_entry_value_at(self : Function[Inst], parameter : Int) ->
    VirtualReg

    Returns a function parameter as a canonical allocation virtual register.

    Function::allocation_instruction_clobbers

    fn[Inst] Function::allocation_instruction_clobbers(self : Function[Inst], instruction : Int) -> ArrayView[
    PhysicalReg
    ]

    Function::allocation_instruction_operands

    fn[Inst] Function::allocation_instruction_operands(self : Function[Inst], instruction : Int) -> ArrayView[
    AllocationOperand
    ]

    Function::allocation_layout_block_id_at

    fn[Inst] Function::allocation_layout_block_id_at(self : Function[Inst], block : Int) -> Int

    Returns the stable block id at a valid dense layout index.

    Function::allocation_value_type_at

    fn[Inst] Function::allocation_value_type_at(self : Function[Inst], value : Int) ->
    ValueType

    Returns the allocation type for a valid dense value id.

    Allocation consumers call these indexed accessors only after selected VCode validation, so invalid indices are programmer errors.

    Function::allocation_vreg

    fn[Inst] Function::allocation_vreg(self : Function[Inst], value : Value) ->
    VirtualReg
    ?

    Function::before

    fn[Inst] Function::before(self : Function[Inst], instruction : Instruction) -> ProgramPoint?

    Function::block_at

    fn[Inst] Function::block_at(self : Function[Inst], index : Int) -> Block?

    Function::block_body

    fn[Inst] Function::block_body(self : Function[Inst], block : Block) -> Array[Instruction]

    Function::block_count

    fn[Inst] Function::block_count(self : Function[Inst]) -> Int

    Function::block_index

    fn[Inst] Function::block_index(self : Function[Inst], block : Block) -> Int?

    Function::block_instruction_at

    fn[Inst] Function::block_instruction_at(self : Function[Inst], block : Block, index : Int) -> Instruction?

    Returns a body instruction or the block terminator by linear block index.

    Function::block_instruction_count

    fn[Inst] Function::block_instruction_count(self : Function[Inst], block : Block) -> Int

    Number of instructions in a block, including its terminator when present.

    Function::block_parameter_at

    fn[Inst] Function::block_parameter_at(self : Function[Inst], block : Block, index : Int) -> Value?

    Function::block_parameter_count

    fn[Inst] Function::block_parameter_count(self : Function[Inst], block : Block) -> Int

    Function::block_parameters

    fn[Inst] Function::block_parameters(self : Function[Inst], block : Block) -> Array[Value]

    Function::block_terminator

    fn[Inst] Function::block_terminator(self : Function[Inst], block : Block) -> Instruction?

    Function::entry_block

    fn[Inst] Function::entry_block(self : Function[Inst]) -> Block

    Function::instruction

    fn[Inst] Function::instruction(self : Function[Inst], instruction : Instruction) -> Inst?

    Function::instruction_allocation_operand_at

    fn[Inst] Function::instruction_allocation_operand_at(self : Function[Inst], instruction : Instruction, index : Int) ->
    AllocationOperand
    ?

    Function::instruction_at

    fn[Inst] Function::instruction_at(self : Function[Inst], index : Int) -> Instruction?

    Function::instruction_clobber_at

    fn[Inst] Function::instruction_clobber_at(self : Function[Inst], instruction : Instruction, index : Int) ->
    PhysicalReg
    ?

    Function::instruction_clobber_count

    fn[Inst] Function::instruction_clobber_count(self : Function[Inst], instruction : Instruction) -> Int

    Function::instruction_clobbers

    fn[Inst] Function::instruction_clobbers(self : Function[Inst], instruction : Instruction) -> Array[
    PhysicalReg
    ]

    Function::instruction_count

    fn[Inst] Function::instruction_count(self : Function[Inst]) -> Int

    Function::instruction_index

    fn[Inst] Function::instruction_index(self : Function[Inst], instruction : Instruction) -> Int?

    Function::instruction_is_terminator

    fn[Inst] Function::instruction_is_terminator(self : Function[Inst], instruction : Instruction) -> Bool

    Function::instruction_metadata

    fn[Inst] Function::instruction_metadata(self : Function[Inst], instruction : Instruction) -> InstructionMetadata?

    Function::instruction_operand_at

    fn[Inst] Function::instruction_operand_at(self : Function[Inst], instruction : Instruction, index : Int) -> Operand?

    Function::instruction_operand_count

    fn[Inst] Function::instruction_operand_count(self : Function[Inst], instruction : Instruction) -> Int

    Function::instruction_operands

    fn[Inst] Function::instruction_operands(self : Function[Inst], instruction : Instruction) -> Array[Operand]

    Function::instruction_results

    fn[Inst] Function::instruction_results(self : Function[Inst], instruction : Instruction) -> Array[Value]

    Function::instruction_successor_argument_at

    fn[Inst] Function::instruction_successor_argument_at(self : Function[Inst], instruction : Instruction, successor : Int, argument : Int) -> Value?

    Function::instruction_successor_argument_count

    fn[Inst] Function::instruction_successor_argument_count(self : Function[Inst], instruction : Instruction, successor : Int) -> Int

    Function::instruction_successor_at

    fn[Inst] Function::instruction_successor_at(self : Function[Inst], instruction : Instruction, index : Int) -> Edge?

    Function::instruction_successor_count

    fn[Inst] Function::instruction_successor_count(self : Function[Inst], instruction : Instruction) -> Int

    Function::instruction_successor_target

    fn[Inst] Function::instruction_successor_target(self : Function[Inst], instruction : Instruction, successor : Int) -> Block?

    Function::instruction_successors

    fn[Inst] Function::instruction_successors(self : Function[Inst], instruction : Instruction) -> Array[Edge]

    Function::layout

    fn[Inst] Function::layout(self : Function[Inst]) -> Array[Block]

    Function::layout_block_at

    fn[Inst] Function::layout_block_at(self : Function[Inst], index : Int) -> Block?

    Function::name

    fn[Inst] Function::name(self : Function[Inst]) -> String

    Function::parameter_at

    fn[Inst] Function::parameter_at(self : Function[Inst], index : Int) -> Value?

    Function::parameter_count

    fn[Inst] Function::parameter_count(self : Function[Inst]) -> Int

    Function::program_point_instruction

    fn[Inst] Function::program_point_instruction(self : Function[Inst], point : ProgramPoint) -> Instruction?

    Function::protocol

    Function::result_types

    Function::set_layout

    fn[Inst] Function::set_layout(self : Function[Inst], layout : Array[Block]) -> Unit raise VCodeBuildError

    Function::summary

    fn[Inst :
    Debug
    ] Function::summary(self : Function[Inst]) -> String

    Function::value_at

    fn[Inst] Function::value_at(self : Function[Inst], index : Int) -> Value?

    Function::value_count

    fn[Inst] Function::value_count(self : Function[Inst]) -> Int

    Function::value_index

    fn[Inst] Function::value_index(self : Function[Inst], value : Value) -> Int?

    Function::value_type

    fn[Inst] Function::value_type(self : Function[Inst], value : Value) ->
    ValueType
    ?

    Input

    Input::any

    fn Input::any(value : Value) -> Input

    Input::any_location

    fn Input::any_location(value : Value) -> Input

    Keep an input in its allocated register or spill slot. This is intended for target operations, such as ABI argument setup, whose emitter can consume a stack-resident value directly instead of requiring every input in a register at the same program point.

    Input::with_preference

    fn Input::with_preference(self : Input, preference :
    PhysicalReg
    ) -> Input

    Prefer a physical register without making it an allocation constraint.

    Input::with_timing

    Instruction

    pub struct Instruction {
    // private fields
    }

    impl Eq for Instruction
    impl Show for Instruction

    Instruction::equal

    fn Instruction::equal(self : Instruction, other : Instruction) -> Bool

    Instruction::not_equal

    fn Instruction::not_equal(x : Instruction, y : Instruction) -> Bool

    Instruction::output

    fn Instruction::output(self : Instruction, logger : &Logger) -> Unit

    Instruction::to_repr

    Instruction::to_string

    fn Instruction::to_string(self : Instruction) -> String

    Location

    pub(all) enum Location {
    Register(
    PhysicalReg
    )
    Stack(StackSlot)
    } derive(Eq)

    Location::equal

    fn Location::equal(Location, Location) -> Bool

    Location::not_equal

    fn Location::not_equal(x : Location, y : Location) -> Bool

    Location::to_repr

    OperandConstraint

    pub(all) enum OperandConstraint {
    Any
    AnyLocation
    Fixed(
    PhysicalReg
    )
    TiedTo(Int)
    } derive(Eq,
    Debug
    )

    OperandConstraint::equal

    OperandConstraint::not_equal

    fn OperandConstraint::not_equal(x : OperandConstraint, y : OperandConstraint) -> Bool

    Output

    Output::any_location

    Materialize the result directly in its stable register or stack home. This is intended for target ABI pseudos whose emitter owns the transfer from an implicit incoming location.

    Output::tied

    fn Output::tied(ty :
    ValueType
    , operand_index : Int) -> Output

    Output::with_preference

    Prefer a physical register without making it an allocation constraint.

    Output::with_timing

    ParallelMove

    ParallelMove::equal

    ParallelMove::not_equal

    fn ParallelMove::not_equal(x : ParallelMove, y : ParallelMove) -> Bool

    PointPlacement

    pub(all) enum PointPlacement {
    Before
    After
    } derive(Eq,
    Debug
    )

    PointPlacement::equal

    PointPlacement::not_equal

    fn PointPlacement::not_equal(x : PointPlacement, y : PointPlacement) -> Bool

    ProgramPoint

    pub struct ProgramPoint {
    // private fields
    }

    impl Eq for ProgramPoint

    ProgramPoint::equal

    fn ProgramPoint::equal(self : ProgramPoint, other : ProgramPoint) -> Bool

    ProgramPoint::instruction

    fn ProgramPoint::instruction(self : ProgramPoint) -> Instruction

    ProgramPoint::not_equal

    fn ProgramPoint::not_equal(x : ProgramPoint, y : ProgramPoint) -> Bool

    ProgramPoint::placement

    fn ProgramPoint::placement(self : ProgramPoint) -> PointPlacement

    ProgramPoint::to_repr

    RegallocLoopStatistics

    pub(all) struct RegallocLoopStatistics {
    queue_pops : Int
    register_probes : Int
    occupied_segments_scanned : Int
    conflicts : Int
    evictions : Int
    bundle_splits : Int
    second_chance_attempts : Int
    max_queue_length : Int
    } derive(Eq,
    Debug
    )

    Deterministic counters for the allocator's bundle-probing loop.

    RegallocLoopStatistics::equal

    RegallocLoopStatistics::not_equal

    ResolvedCallTransferPlan

    pub struct ResolvedCallTransferPlan {
    stack_transfers : Array[StackArgumentTransfer]
    register_moves : ResolvedMovePlan
    } derive(Eq,
    Debug
    )

    ResolvedCallTransferPlan::equal

    ResolvedCallTransferPlan::not_equal

    ResolvedMovePlan

    pub struct ResolvedMovePlan {
    steps : Array[ResolvedMoveStep]
    requires_emergency : Bool
    } derive(Eq,
    Debug
    )

    ResolvedMovePlan::empty

    ResolvedMovePlan::equal

    ResolvedMovePlan::not_equal

    fn ResolvedMovePlan::not_equal(x : ResolvedMovePlan, y : ResolvedMovePlan) -> Bool

    ResolvedMoveStep

    ResolvedMoveStep::equal

    ResolvedMoveStep::not_equal

    fn ResolvedMoveStep::not_equal(x : ResolvedMoveStep, y : ResolvedMoveStep) -> Bool

    StackArgumentTransfer

    StackArgumentTransfer::equal

    StackArgumentTransfer::not_equal

    StackSlot

    pub struct StackSlot {
    // private fields
    }

    impl Eq for StackSlot

    StackSlot::equal

    fn StackSlot::equal(self : StackSlot, other : StackSlot) -> Bool

    StackSlot::not_equal

    fn StackSlot::not_equal(x : StackSlot, y : StackSlot) -> Bool

    StackSlot::to_repr

    TargetCompileEvent

    pub(all) enum TargetCompileEvent {
    TargetAnalysisStarted
    TargetConstructionStarted
    TargetValidationStarted
    TargetCommonValidationStarted
    TargetIsaValidationStarted
    TargetSealingStarted
    TargetSelectionFinished
    RegallocStarted
    RegallocPhaseStarted(String)
    RegallocPhasesFinished
    RegallocLoopMeasured(RegallocLoopStatistics)
    RegallocFinished(AllocationStatistics)
    FramePlanningStarted
    FramePlanningFinished
    EmissionStarted
    EmissionFinished
    } derive(Eq,
    Debug
    )

    Target-compilation boundaries exposed to an embedding-owned observer.

    The observer must not mutate compiler inputs from inside the callback.

    TargetCompileEvent::equal

    TargetCompileEvent::not_equal

    Value

    pub struct Value {
    // private fields
    }

    impl Eq for Value
    impl Show for Value

    Value::equal

    fn Value::equal(self : Value, other : Value) -> Bool

    Value::not_equal

    fn Value::not_equal(x : Value, y : Value) -> Bool

    Value::output

    fn Value::output(self : Value, logger : &Logger) -> Unit

    Value::to_repr

    Value::to_string

    fn Value::to_string(self : Value) -> String

    plan_call_transfers

    fn plan_call_transfers(allocation : Allocation, transfers : Array[CallTransfer], outgoing_stack_start : Int, outgoing_stack_size : Int, scratch_int : Array[
    PhysicalReg
    ], scratch_fp : Array[
    PhysicalReg
    ], protected_locations : Array[Location]) -> CallTransferPlan raise CallTransferError

    plan_resolved_call_transfers

    fn plan_resolved_call_transfers(allocation : Allocation, transfers : Array[CallTransfer], outgoing_stack_start : Int, outgoing_stack_size : Int, stack_scratch_int : Array[
    PhysicalReg
    ], stack_scratch_fp : Array[
    PhysicalReg
    ], move_scratch_int :
    PhysicalReg
    , move_scratch_fp :
    PhysicalReg
    , protected_locations : Array[Location]) -> ResolvedCallTransferPlan raise CallTransferError

    verify_allocated

    fn[Inst] verify_allocated(function : Function[Inst], allocation : Allocation) -> Unit raise AllocationVerifyError

    verify_allocation_invariants

    fn[Inst] verify_allocation_invariants(function : Function[Inst], allocation : Allocation) -> Unit raise AllocationVerifyError

    Verifies allocation-specific invariants for VCode that has already passed verify_selected. The caller must not mutate function between the two checks.

    verify_emission_input

    fn[Inst] verify_emission_input(function : Function[Inst], allocation : Allocation, frame : FrameLayout) -> Unit raise EmissionVerifyError

    verify_framed

    fn[Inst] verify_framed(function : Function[Inst], allocation : Allocation, frame : FrameLayout) -> Unit raise FrameVerifyError

    verify_selected

    fn[Inst] verify_selected(function : Function[Inst]) -> Unit raise VCodeVerifyError