Target-independent native lowering, VCode, and code-object infrastructure
| Package | Responsibility |
|---|---|
| Milky2018/vcode/native_types | Canonical native value types, signatures, calls, symbols, operation effects, traps, safepoints, source locations, and stack-map metadata. |
| Milky2018/vcode/native_lowering | Streaming producer-to-target protocol, target-neutral operations, transient value and block handles, and call-ABI elaboration. |
| Milky2018/vcode/allocation_types | Minimal 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/vcode | Dense target VCode, checked construction, allocation and frame side tables, staged verification, call-transfer planning, and parallel-move resolution. |
| Milky2018/vcode/code_object | Verified machine-code bytes with typed relocations, source and trap sites, safepoints and roots, and target-neutral unwind directives. |
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///|
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")
}///|
let object = @code_object.build(@code_object.X64, [b'\xc3'])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)impl Show for AllocationVerifyErrorpub 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)impl Show for EmissionVerifyErrorpub 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)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)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)pub struct Allocation {
// private fields
}fn Allocation::add_safepoint_root(self : Allocation, instruction : Instruction, value : Value, location : Location) -> Boolfn Allocation::allocated_operand_location_at(self : Allocation, instruction : Int, operand : Int) -> AllocationLocation?fn Allocation::assign_operand(self : Allocation, instruction : Instruction, operand_index : Int, reg : PhysicalReg) -> Boolfn Allocation::assign_operand_location(self : Allocation, instruction : Instruction, operand_index : Int, location : Location) -> Boolfn Allocation::create_stack_slot(self : Allocation, ty : ValueType, size : Int, alignment : Int) -> StackSlotfn Allocation::edge_edits_at(self : Allocation, source : Block, successor_index : Int) -> ArrayView[Edit]fn Allocation::edits_at(self : Allocation, instruction : Instruction, placement : PointPlacement) -> ArrayView[Edit]fn Allocation::operand_location(self : Allocation, instruction : Instruction, operand_index : Int) -> Location?fn Allocation::safepoint_roots(self : Allocation, instruction : Instruction) -> Array[(Value, Location)]pub struct AllocationBuilder[Inst] {
// private fields
}fn[Inst] AllocationBuilder::add_edge_transfer(self : AllocationBuilder[Inst], source_block : Int, successor : Int, value : Int, from : AllocationLocation, to : AllocationLocation) -> Boolfn[Inst] AllocationBuilder::add_safepoint_root(self : AllocationBuilder[Inst], instruction : Int, value : Int) -> Boolfn[Inst] AllocationBuilder::add_transfer(self : AllocationBuilder[Inst], instruction : Int, placement : PointPlacement, value : Int, from : AllocationLocation, to : AllocationLocation) -> Boolfn[Inst] AllocationBuilder::assign_operand(self : AllocationBuilder[Inst], instruction : Int, operand : Int, location : AllocationLocation) -> Boolfn[Inst] AllocationBuilder::assign_value(self : AllocationBuilder[Inst], value : Int, location : AllocationLocation) -> Boolfn[Inst] AllocationBuilder::create_stack_slot(self : AllocationBuilder[Inst], value : Int, size : Int, alignment : Int) -> Intfn[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]?fn[Inst] AllocationBuilder::operand_value_at(self : AllocationBuilder[Inst], instruction : Int, operand : Int) -> Intfn[Inst] AllocationBuilder::value_location(self : AllocationBuilder[Inst], value : Int) -> AllocationLocation?pub struct Block {
// private fields
}pub struct Builder[Inst] {
// private fields
}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 VCodeBuildErrorfn[Inst] Builder::block_parameter(self : Builder[Inst], block : Block, index : Int) -> Value raise VCodeBuildErrorfn[Inst] Builder::set_terminator(self : Builder[Inst], block : Block, inst : Inst, inputs : Array[Input], successors : Array[Edge], clobbers : Array[PhysicalReg], metadata : InstructionMetadata) -> Instruction raise VCodeBuildErrorpub struct CallTransfer {
// private fields
}fn CallTransfer::to_register(ty : ValueType, source : Location, destination : PhysicalReg) -> CallTransferpub struct CallTransferPlan {
stack_transfers : Array[StackArgumentTransfer]
register_moves : Array[ParallelMove]
} derive(Eq, Debug)pub struct CheckedBuilder[Inst] {
// private fields
}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 VCodeBuildErrorfn[Inst] CheckedBuilder::block_parameter(self : CheckedBuilder[Inst], block : Block, index : Int) -> Value raise VCodeBuildErrorfn[Inst] CheckedBuilder::create_block(self : CheckedBuilder[Inst], parameter_types : Array[ValueType]) -> Blockfn[Inst] CheckedBuilder::finish(self : CheckedBuilder[Inst]) -> Function[Inst] raise VCodeBuildErrorfn[Inst] CheckedBuilder::new(name : String, parameter_types : Array[ValueType]) -> CheckedBuilder[Inst]fn[Inst] CheckedBuilder::new_with_protocol(name : String, protocol : CallProtocol, parameter_types : Array[ValueType], result_types : Array[ValueType]) -> CheckedBuilder[Inst]fn[Inst] CheckedBuilder::new_with_results(name : String, parameter_types : Array[ValueType], result_types : Array[ValueType]) -> CheckedBuilder[Inst]fn[Inst] CheckedBuilder::parameter(self : CheckedBuilder[Inst], index : Int) -> Value raise VCodeBuildErrorfn[Inst] CheckedBuilder::set_terminator(self : CheckedBuilder[Inst], block : Block, inst : Inst, inputs : Array[Input], successors : Array[Edge], clobbers : Array[PhysicalReg], metadata : InstructionMetadata) -> Instruction raise VCodeBuildErrorfn Edit::register_move(point : ProgramPoint, value : Value, from : PhysicalReg, to : PhysicalReg) -> Editpub(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)pub struct FrameLayout {
// private fields
}fn[Inst] FrameLayout::new(function : Function[Inst], allocation : Allocation, frame_size : Int, alignment : Int) -> FrameLayoutpub struct Function[Inst] {
// private fields
}fn[Inst] Function::allocation_block_parameter_at(self : Function[Inst], block : Int, parameter : Int) -> VirtualRegfn[Inst] Function::allocation_edge_argument_at(self : Function[Inst], block : Int, successor : Int, argument : Int) -> VirtualRegfn[Inst] Function::allocation_instruction_clobbers(self : Function[Inst], instruction : Int) -> ArrayView[PhysicalReg]fn[Inst] Function::allocation_instruction_operands(self : Function[Inst], instruction : Int) -> ArrayView[AllocationOperand]fn[Inst] Function::block_instruction_at(self : Function[Inst], block : Block, index : Int) -> Instruction?fn[Inst] Function::instruction_allocation_operand_at(self : Function[Inst], instruction : Instruction, index : Int) -> AllocationOperand?fn[Inst] Function::instruction_clobber_at(self : Function[Inst], instruction : Instruction, index : Int) -> PhysicalReg?fn[Inst] Function::instruction_clobber_count(self : Function[Inst], instruction : Instruction) -> Intfn[Inst] Function::instruction_clobbers(self : Function[Inst], instruction : Instruction) -> Array[PhysicalReg]fn[Inst] Function::instruction_is_terminator(self : Function[Inst], instruction : Instruction) -> Boolfn[Inst] Function::instruction_metadata(self : Function[Inst], instruction : Instruction) -> InstructionMetadata?fn[Inst] Function::instruction_operand_at(self : Function[Inst], instruction : Instruction, index : Int) -> Operand?fn[Inst] Function::instruction_operand_count(self : Function[Inst], instruction : Instruction) -> Intfn[Inst] Function::instruction_operands(self : Function[Inst], instruction : Instruction) -> Array[Operand]fn[Inst] Function::instruction_results(self : Function[Inst], instruction : Instruction) -> Array[Value]fn[Inst] Function::instruction_successor_argument_at(self : Function[Inst], instruction : Instruction, successor : Int, argument : Int) -> Value?fn[Inst] Function::instruction_successor_argument_count(self : Function[Inst], instruction : Instruction, successor : Int) -> Intfn[Inst] Function::instruction_successor_at(self : Function[Inst], instruction : Instruction, index : Int) -> Edge?fn[Inst] Function::instruction_successor_count(self : Function[Inst], instruction : Instruction) -> Intfn[Inst] Function::instruction_successor_target(self : Function[Inst], instruction : Instruction, successor : Int) -> Block?fn[Inst] Function::instruction_successors(self : Function[Inst], instruction : Instruction) -> Array[Edge]fn[Inst] Function::program_point_instruction(self : Function[Inst], point : ProgramPoint) -> Instruction?fn[Inst] Function::set_layout(self : Function[Inst], layout : Array[Block]) -> Unit raise VCodeBuildErrorpub struct Input {
value : Value
constraint : OperandConstraint
preference : PhysicalReg?
timing : OperandTiming
}pub struct Instruction {
// private fields
}pub struct InstructionMetadata {
source : SourceLocation?
trap : TrapReason?
safepoint : SafepointKind?
live_gc_roots : Array[Value]
symbol : SymbolReference?
stack_map : StackMapMetadata?
}fn InstructionMetadata::new(source? : SourceLocation, trap? : TrapReason, safepoint? : SafepointKind, live_gc_roots? : Array[Value], symbol? : SymbolReference, stack_map? : StackMapMetadata) -> InstructionMetadatapub struct Operand {
value : Value
role : OperandRole
constraint : AllocationConstraint
preference : PhysicalReg?
timing : OperandTiming
tie_id : Int
} derive(Eq, Debug)pub struct Output {
ty : ValueType
constraint : OperandConstraint
preference : PhysicalReg?
timing : OperandTiming
}pub struct ProgramPoint {
// private fields
}fn RegallocLoopStatistics::not_equal(x : RegallocLoopStatistics, y : RegallocLoopStatistics) -> Boolpub struct ResolvedCallTransferPlan {
stack_transfers : Array[StackArgumentTransfer]
register_moves : ResolvedMovePlan
} derive(Eq, Debug)fn ResolvedCallTransferPlan::not_equal(x : ResolvedCallTransferPlan, y : ResolvedCallTransferPlan) -> Boolpub struct ResolvedMovePlan {
steps : Array[ResolvedMoveStep]
requires_emergency : Bool
} derive(Eq, Debug)pub(all) enum ResolvedMoveStep {
Transfer(ParallelMove)
SpillScratchToEmergency(ty~ : ValueType, scratch~ : PhysicalReg)
ReloadScratchFromEmergency(ty~ : ValueType, scratch~ : PhysicalReg)
} derive(Eq, Debug)pub struct StackArgumentTransfer {
ty : ValueType
source : Location
offset : Int
scratch : PhysicalReg?
} derive(Eq, Debug)pub struct StackSlot {
// private fields
}pub(all) enum SymbolReference {
Code(CodeSymbol)
External(ExternalSymbol)
Data(DataSymbol)
} derive(Eq, Debug)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)pub struct Value {
// private fields
}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 CallTransferErrorfn plan_parallel_moves(moves : Array[ParallelMove], scratch_int : PhysicalReg, scratch_fp : PhysicalReg) -> ResolvedMovePlan raise MoveResolveErrorfn 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 CallTransferErrorfn resolve_parallel_moves(moves : Array[ParallelMove], scratch_int : Array[PhysicalReg], scratch_fp : Array[PhysicalReg]) -> Array[ParallelMove] raise MoveResolveErrorfn[Inst] verify_allocated(function : Function[Inst], allocation : Allocation) -> Unit raise AllocationVerifyErrorfn[Inst] verify_allocation_invariants(function : Function[Inst], allocation : Allocation) -> Unit raise AllocationVerifyErrorfn[Inst] verify_emission_input(function : Function[Inst], allocation : Allocation, frame : FrameLayout) -> Unit raise EmissionVerifyErrorfn[Inst] verify_framed(function : Function[Inst], allocation : Allocation, frame : FrameLayout) -> Unit raise FrameVerifyErrorInstall
Download zipTarget-independent native lowering, VCode, and code-object infrastructure