aarch64_target

    AArch64 direct MilkIR target pipeline to native code

    aarch64
    compiler
    codegen
    jit
    Download zip
    Author
    Version
    0.15.0
    License
    Apache-2.0
    Last updated
    10 days ago
    Downloads
    152

    #aarch64_target

    AArch64 backend for direct MilkIR instruction selection.

    This module owns AArch64 instruction selection, validation and lowering of an embedding-provided internal ABI contract, register allocation policy, frame layout, machine-code emission, relocations, veneers, and final linking.

    #Package

    • Milky2018/aarch64_target: AArch64 Target VCode, lowering, allocation, frame layout, emission, and linking.

    #When to use it

    Use this module as the target sink for Milky2018/milkir/native, then install its generated code object through the embedding runtime.

    Environment fields are materialized at each lowered occurrence. MilkIR owns whether stable fields remain separate rematerializable values; the target does not merge them with distance or register-pressure heuristics. No physical register is reserved for embedding context data.

    #Example: define the internal ABI

    ///|
    test "validate the AArch64 internal ABI" {
    InternalAbi::new(
    0,
    8,
    [1, 2, 3, 4, 5, 6, 7],
    [0, 1, 2, 3, 4, 5, 6, 7],
    [0, 1, 2, 3, 4, 5, 6, 7],
    [0, 1, 2, 3, 4, 5, 6, 7],
    )
    |> ignore
    }

    #Integration

    Finish a DirectLoweringSession, then use compile_selected for the complete AArch64 target pipeline. It produces a verified Milky2018/vcode/code_object value. Runtime symbol resolution, relocation application, and executable-memory ownership remain responsibilities of the embedding application.

    compile performs allocation, frame planning, and emission without repeating checkpoint validation. Its optional on_event callback reports generic stage boundaries and a read-only allocation summary so an embedding can collect metrics without coupling this module to a product metrics system. The callback must not mutate compiler inputs.

    Internal functions use the tail-call convention: an ordinary internal caller places stack arguments in its reserved outgoing area, the callee pops that incoming area on return, and the call pseudo immediately restores the caller's frame-base SP. A function containing true tail calls enlarges its incoming area in the prologue to the maximum tail-callee requirement, then reuses that area when transferring control. Platform calls continue to use ordinary AAPCS64 caller-owned stack arguments.

    Parallel moves reserve X15 and V18 as one transfer scratch per register bank. X16 remains stack-address-only, while X17 and V16/V17 serve instruction and regalloc spill needs. A stack cycle that temporarily needs the live transfer scratch receives one verified 16-byte emergency frame area; ordinary frames do not pay for it.

    AArch64AllocationError

    AArch64AllocationError::output

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

    AArch64AllocationError::to_string

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

    AArch64CompileError

    pub suberror AArch64CompileError {
    TargetValidationFailed(cause~ : TargetVCodeVerifyError)
    AllocationFailed(cause~ : AArch64AllocationError)
    FramePlanningFailed(cause~ : AArch64FrameError)
    EmissionFailed(cause~ : AArch64EmitError)
    } derive(
    Debug
    )

    AArch64CompileError::output

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

    AArch64CompileError::to_string

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

    AArch64EmitError

    pub suberror AArch64EmitError {
    InvalidFrame(cause~ : AArch64FrameError)
    InvalidCodeObject(cause~ :
    CodeObjectVerifyError
    )
    InvalidParallelMove(cause~ :
    MoveResolveError
    )
    InvalidCallTransfer(cause~ :
    CallTransferError
    )
    UnresolvedStackMove
    MissingStackObjectArea
    MissingResultArea
    MissingEmergencyMoveArea
    UnexpectedStackOperand(instruction~ :
    Instruction
    , operand~ : Int)
    FrameOffsetOutOfRange(offset~ : Int)
    InvalidScalarMemoryAccess
    InvalidFloatInstruction
    InvalidVectorInstruction
    InvalidConversionInstruction
    BranchTargetMissing(block~ :
    Block
    )
    BranchLabelUnbound(label~ : Int)
    BranchSpanNotFixed(offset~ : Int)
    BranchOutOfRange(offset~ : Int, bits~ : Int)
    } derive(
    Debug
    )

    AArch64EmitError::output

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

    AArch64EmitError::to_string

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

    AArch64FrameError

    pub suberror AArch64FrameError {
    InvalidAllocation(cause~ : AArch64AllocationError)
    InvalidGenericFrame(cause~ :
    FrameVerifyError
    )
    InvalidSavedRegister(reg~ :
    PhysicalReg
    , offset~ : Int)
    InvalidStackSlot(slot~ :
    StackSlot
    )
    OutgoingAreaMismatch(expected~ : Int, actual~ : Int)
    ResultAreaMismatch(expected~ : Int, actual~ : Int)
    TailAreaMismatch(expected_incoming~ : Int, actual_incoming~ : Int, expected_tail~ : Int, actual_tail~ : Int)
    InvalidStackObjectArea(message~ : String)
    MovePlanningFailed(cause~ :
    MoveResolveError
    )
    InvalidEmergencyMoveArea(offset~ : Int?)
    StaleAllocation(expected_edits~ : Int, actual_edits~ : Int)
    SavedRegisterSetMismatch
    } derive(
    Debug
    )

    AArch64FrameError::output

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

    AArch64FrameError::to_string

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

    AArch64LinkError

    pub suberror AArch64LinkError {
    InvalidCodeObject(message~ : String)
    InvalidCodeBase(address~ : Int64)
    UnresolvedRelocation(index~ : Int)
    RelocationOutOfRange(index~ : Int)
    UnsupportedRelocation(index~ : Int)
    } derive(Eq,
    Debug
    )

    AArch64LinkError::equal

    AArch64LinkError::not_equal

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

    AArch64LinkError::output

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

    AArch64LinkError::to_string

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

    AArch64LowerError

    pub suberror AArch64LowerError {
    UnsupportedOperation(block_index~ : Int, instruction_index~ : Int, operation~ :
    Operation
    )
    UnsupportedAbi(message~ : String)
    BuildFailure(cause~ :
    VCodeBuildError
    )
    InvalidTarget(cause~ : TargetVCodeVerifyError)
    } derive(
    Debug
    )

    AArch64LowerError::output

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

    AArch64LowerError::to_string

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

    InternalAbiError

    pub suberror InternalAbiError {
    InvalidRegister(role~ : String, index~ : Int)
    DuplicateRegister(role~ : String, index~ : Int)
    ContextRegisterReused(index~ : Int)
    ResultAreaRegisterReused(index~ : Int)
    InvalidSignature(message~ : String)
    } derive(Eq,
    Debug
    )

    InternalAbiError::equal

    InternalAbiError::not_equal

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

    InternalAbiError::output

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

    InternalAbiError::to_string

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

    TargetVCodeVerifyError

    pub suberror TargetVCodeVerifyError {
    CommonFailure(cause~ :
    VCodeVerifyError
    )
    InvalidInstruction(instruction~ :
    Instruction
    , message~ : String)
    } derive(Eq,
    Debug
    )

    TargetVCodeVerifyError::equal

    TargetVCodeVerifyError::not_equal

    TargetVCodeVerifyError::output

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

    TargetVCodeVerifyError::to_string

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

    AArch64Condition

    pub(all) enum AArch64Condition {
    Eq
    Ne
    Lt
    Le
    Gt
    Ge
    Lo
    Ls
    Hi
    Hs
    } derive(Eq,
    Debug
    )

    AArch64Condition::equal

    AArch64Condition::not_equal

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

    AArch64FloatBinary

    pub(all) enum AArch64FloatBinary {
    Add
    Sub
    Mul
    Div
    Min
    Max
    CopySign
    } derive(Eq,
    Debug
    )

    AArch64FloatBinary::equal

    AArch64FloatBinary::not_equal

    AArch64FloatCondition

    pub(all) enum AArch64FloatCondition {
    Equal
    NotEqual
    LessThan
    LessOrEqual
    GreaterThan
    GreaterOrEqual
    Ordered
    Unordered
    } derive(Eq,
    Debug
    )

    AArch64FloatCondition::equal

    AArch64FloatCondition::not_equal

    AArch64FloatTernary

    pub(all) enum AArch64FloatTernary {
    Fmadd
    Fmsub
    Fnmadd
    Fnmsub
    } derive(Eq,
    Debug
    )

    AArch64FloatTernary::equal

    AArch64FloatTernary::not_equal

    AArch64FloatTrapCondition

    pub(all) enum AArch64FloatTrapCondition {
    Unordered
    LessThan
    LessOrEqual
    GreaterOrEqual
    } derive(Eq,
    Debug
    )

    AArch64FloatTrapCondition::equal

    AArch64FloatTrapCondition::not_equal

    AArch64FloatUnary

    pub(all) enum AArch64FloatUnary {
    Negate
    Absolute
    SquareRoot
    Ceil
    Floor
    Truncate
    Nearest
    } derive(Eq,
    Debug
    )

    AArch64FloatUnary::equal

    AArch64FloatUnary::not_equal

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

    AArch64Frame

    pub struct AArch64Frame {
    // private fields
    }

    AArch64Frame::alignment

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

    AArch64Frame::emergency_move_offset

    fn AArch64Frame::emergency_move_offset(self : AArch64Frame) -> Int?

    AArch64Frame::frame_size

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

    AArch64Frame::incoming_args_size

    fn AArch64Frame::incoming_args_size(self : AArch64Frame) -> Int

    AArch64Frame::outgoing_args_size

    fn AArch64Frame::outgoing_args_size(self : AArch64Frame) -> Int

    AArch64Frame::saved_registers

    AArch64Frame::slot_offset

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

    AArch64Frame::stack_object_offset

    fn AArch64Frame::stack_object_offset(self : AArch64Frame, object : AArch64StackObject) -> Int?

    AArch64Frame::summary

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

    AArch64Frame::tail_args_size

    fn AArch64Frame::tail_args_size(self : AArch64Frame) -> Int

    AArch64Inst

    pub(all) enum AArch64Inst {
    IncomingReg(
    ValueType
    ,
    PhysicalReg
    )
    IncomingStack(
    ValueType
    , Int)
    IncomingResultArea(
    PhysicalReg
    )
    IncomingCallResult(
    ValueType
    ,
    PhysicalReg
    )
    IncomingCallAreaResult(
    ValueType
    , Int)
    OutgoingReg(
    ValueType
    ,
    PhysicalReg
    )
    OutgoingAreaResult(
    ValueType
    , Int)
    KeepAlive(
    ValueType
    )
    LoadConstant(GprWidth, UInt64)
    LoadVectorConstant(UInt64, UInt64)
    LoadNull(
    ValueType
    )
    LoadAddress(AArch64Address)
    StackAddress(AArch64StackObject)
    LoadFloatConstant(
    ValueType
    , UInt64)
    Move(
    ValueType
    )
    CarrierMove(
    ValueType
    ,
    ValueType
    )
    Select(
    ValueType
    )
    SpectreGuard
    VectorSelect
    VectorSplat(
    VectorLane
    )
    VectorExtractLane(
    VectorLane
    , Int,
    Signedness
    ?)
    VectorReplaceLane(
    VectorLane
    , Int)
    VectorShuffle(FixedArray[Int])
    VectorSwizzle
    VectorBitwise(
    VectorBitwiseOp
    )
    VectorIntUnary(
    VectorLane
    , AArch64VectorIntUnary)
    VectorIntBinary(
    VectorLane
    , AArch64VectorIntBinary)
    VectorIntShift(
    VectorLane
    ,
    VectorIntShiftOp
    )
    VectorIntCompare(
    VectorLane
    ,
    VectorIntComparison
    )
    VectorConvert(AArch64VectorConversion)
    VectorPredicate(AArch64VectorPredicate)
    VectorFloatUnary(
    VectorLane
    ,
    VectorFloatUnaryOp
    )
    VectorFloatBinary(
    VectorLane
    ,
    VectorFloatBinaryOp
    )
    VectorFloatTernary(
    VectorLane
    ,
    FloatTernaryOp
    )
    VectorFloatCompare(
    VectorLane
    ,
    VectorFloatComparison
    )
    VectorPairwiseAddI16x8
    VectorRelaxedDot8To16
    IntUnary(GprWidth, AArch64IntUnary)
    IntBinary(GprWidth, AArch64IntBinary)
    IntBinaryImmediate(GprWidth, AArch64IntBinary, UInt64)
    IntMultiplyAdd(GprWidth)
    IntShiftRegister(GprWidth, AArch64Shift)
    IntShiftImmediate(GprWidth, AArch64Shift, Int)
    IntAddShiftedLeft(GprWidth, Int)
    PopulationCount(GprWidth)
    IntHighMultiply(GprWidth,
    Signedness
    )
    IntWithOverflow(GprWidth,
    IntOverflowOp
    )
    IntRemainder(GprWidth,
    Signedness
    )
    TrapIfZero(GprWidth)
    TrapIfSignedDivOverflow(GprWidth)
    CompareSet(GprWidth, AArch64Condition)
    ReferenceCompareSet(
    ValueType
    , AArch64Condition)
    FloatUnary(
    ValueType
    , AArch64FloatUnary)
    FloatBinary(
    ValueType
    , AArch64FloatBinary)
    FloatTernary(
    ValueType
    , AArch64FloatTernary)
    FloatCompareSet(
    ValueType
    , AArch64FloatCondition)
    TrapIfFloat(
    ValueType
    , AArch64FloatTrapCondition)
    Convert(AArch64Conversion)
    AddAddress
    AddAddressImmediate(UInt64)
    AddAddressUxtw(Int)
    ScalarLoad(
    AccessWidth
    ,
    LoadExtension
    ,
    ValueType
    , UInt64)
    ScalarLoadUxtw(
    AccessWidth
    ,
    LoadExtension
    ,
    ValueType
    , Int)
    ScalarStore(
    AccessWidth
    ,
    ValueType
    , UInt64)
    ScalarStoreUxtw(
    AccessWidth
    ,
    ValueType
    , Int)
    VectorLoad128(UInt64)
    VectorStore128(UInt64)
    VectorLoadSplat(
    VectorLane
    , UInt64)
    VectorLoadExtend(
    VectorLane
    ,
    Signedness
    , UInt64)
    VectorLoadZero(
    AccessWidth
    , UInt64)
    VectorLoadLane(
    VectorLane
    , Int, UInt64)
    VectorStoreLane(
    VectorLane
    , Int, UInt64)
    AtomicLoad(
    AccessWidth
    ,
    ValueType
    )
    AtomicStore(
    AccessWidth
    ,
    ValueType
    )
    AtomicRmw(
    AccessWidth
    ,
    ValueType
    ,
    AtomicRmwOp
    )
    AtomicCompareExchange(
    AccessWidth
    ,
    ValueType
    )
    AtomicFence
    SafepointMarker
    PlatformCall(
    ExternalSymbol
    ,
    Signature
    )
    ReturnsTwicePlatformCall(
    ExternalSymbol
    ,
    Signature
    )
    InternalCall(
    CodeSymbol
    ,
    Signature
    , InternalCallPlan)
    InternalCallIndirect(
    Signature
    , InternalCallPlan)
    TailCallDirect(
    CodeSymbol
    ,
    Signature
    , InternalCallPlan)
    TailCallIndirect(
    Signature
    , InternalCallPlan)
    Jump
    BranchNonZero(GprWidth)
    BranchCompare(GprWidth, AArch64Condition)
    BranchCompareImmediate(GprWidth, AArch64Condition, UInt64)
    Switch(GprWidth, Array[UInt64])
    Trap(
    TrapReason
    )
    Return
    } derive(Eq,
    Debug
    )

    AArch64Inst::equal

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

    AArch64Inst::not_equal

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

    AArch64IntBinary

    pub(all) enum AArch64IntBinary {
    Add
    Sub
    Mul
    And
    Orr
    Eor
    Sdiv
    Udiv
    } derive(Eq,
    Debug
    )

    AArch64IntBinary::equal

    AArch64IntBinary::not_equal

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

    AArch64IntUnary

    pub(all) enum AArch64IntUnary {
    Mvn
    Clz
    Rbit
    Neg
    } derive(Eq,
    Debug
    )

    AArch64IntUnary::equal

    AArch64IntUnary::not_equal

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

    AArch64LinkPlan

    pub struct AArch64LinkPlan {
    // private fields
    } derive(
    Debug
    )

    AArch64LinkPlan::code

    fn AArch64LinkPlan::code(self : AArch64LinkPlan) -> Array[Byte]

    fn AArch64LinkPlan::link(self : AArch64LinkPlan, code_address : Int64, resolve : (
    RelocationTarget
    ) -> Int64?) -> Array[Byte] raise AArch64LinkError

    AArch64LinkPlan::veneer_offsets

    fn AArch64LinkPlan::veneer_offsets(self : AArch64LinkPlan) -> Array[Int]

    AArch64Shift

    pub(all) enum AArch64Shift {
    Lsl
    Asr
    Lsr
    Ror
    } derive(Eq,
    Debug
    )

    AArch64Shift::equal

    AArch64Shift::not_equal

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

    AArch64StackObject

    pub struct AArch64StackObject {
    id : Int
    size : Int
    alignment : Int
    } derive(Eq,
    Debug
    )

    AArch64StackObject::equal

    AArch64StackObject::new

    fn AArch64StackObject::new(id : Int, size : Int, alignment : Int) -> AArch64StackObject

    AArch64StackObject::not_equal

    AArch64VectorIntUnary

    pub(all) enum AArch64VectorIntUnary {
    Absolute
    Negate
    PopulationCount
    ExtendAddPairwise(
    Signedness
    )
    } derive(Eq,
    Debug
    )

    AArch64VectorIntUnary::equal

    AArch64VectorIntUnary::not_equal

    AArch64VectorPredicate

    AArch64VectorPredicate::equal

    AArch64VectorPredicate::not_equal

    CallArgumentLocation

    type CallArgumentLocation derive(Eq,
    Debug
    )

    CallArgumentLocation::equal

    CallArgumentLocation::not_equal

    CallLayout

    type CallLayout derive(Eq,
    Debug
    )

    CallLayout::equal

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

    CallLayout::not_equal

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

    CallResultLocation

    type CallResultLocation derive(Eq,
    Debug
    )

    CallResultLocation::equal

    CallResultLocation::not_equal

    CompilationDiagnostics

    pub(all) struct CompilationDiagnostics {
    target_vcode : String
    allocated_vcode : String
    object :
    UnlinkedCodeObject

    }

    CompilationSession

    pub struct CompilationSession {
    // private fields
    }

    Compiles selected AArch64 VCode through allocation, frame planning, and emission. Each stage validates the invariant it introduces without revalidating invariants already established by this pipeline.

    on_event is an observation-only seam. It must not mutate function or any compiler object reachable while the callback runs.

    CompilationSession::compile_selected

    Compile selected VCode while retaining allocator scratch capacity for the next serial call on this session.

    CompilationSession::new

    DirectLoweringSession

    pub struct DirectLoweringSession {
    // private fields
    }

    DirectLoweringSession::finish_selected

    fn DirectLoweringSession::finish_selected(self : DirectLoweringSession, verify_selected? : Bool) -> SelectedFunction raise AArch64LowerError

    Finish direct selection and return the VCode consumed by target compilation.

    verify_selected=false is reserved for compiler-owned construction paths covered by strict validation in CI. Public callers should keep the default.

    GprWidth

    pub(all) enum GprWidth {
    W32
    W64
    } derive(Eq,
    Debug
    )

    GprWidth::equal

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

    GprWidth::not_equal

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

    GprWidth::to_repr

    InternalAbi

    pub struct InternalAbi {
    // private fields
    }

    InternalAbi::new

    fn InternalAbi::new(context_argument : Int, result_area_argument : Int, integer_arguments : Array[Int], fp_arguments : Array[Int], integer_results : Array[Int], fp_results : Array[Int]) -> InternalAbi raise InternalAbiError

    InternalCallPlan

    pub struct InternalCallPlan {
    // private fields
    } derive(Eq,
    Debug
    )

    InternalCallPlan::equal

    InternalCallPlan::not_equal

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

    LoweringContext

    pub struct LoweringContext {
    // private fields
    }

    LoweringContext::new

    fn LoweringContext::new(internal_abi : InternalAbi) -> LoweringContext

    LoweringContext::with_environment_field

    LoweringContext::with_environment_field_resolver

    SelectedFunction

    pub struct SelectedFunction {
    // private fields
    }

    Opaque evidence that direct AArch64 selection and VCode validation completed.

    compile

    Compile externally supplied AArch64 VCode through the safe validated entry.

    compile_selected

    Compile VCode produced by select without repeating target validation.

    diagnose_selected

    fn diagnose_selected(selected : SelectedFunction) -> CompilationDiagnostics raise AArch64CompileError

    verify_allocation

    verify_frame

    verify_vcode

    fn verify_vcode(function :
    Function
    [AArch64Inst]) -> Unit raise TargetVCodeVerifyError