aarch64_target

AArch64 target pipeline from semantic MachV to native code

aarch64
compiler
codegen
jit
moon add Milky2018/aarch64_target@0.6.2
Download zip
Author
Version
0.6.2
License
Apache-2.0
Last updated
2 days ago
Downloads
77
README

#aarch64_target

AArch64 backend for target-neutral MachV.

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 after producing a verified Milky2018/machv.Function and before installing generated bytes into executable memory.

Environment fields are materialized at each semantic MachV 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

Use this package for the complete AArch64 target pipeline after semantic MachV. It produces a verified Milky2018/machv/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

#
AArch64CompileError

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

#
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
)

#
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?)
SavedRegisterSetMismatch
} derive(
Debug
)

#
AArch64LinkError

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

#
AArch64LowerError

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

#
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
)

#
TargetVCodeVerifyError

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

#
AArch64Condition

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

#
AArch64FloatBinary

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

#
AArch64FloatCondition

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

#
AArch64FloatTernary

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

#
AArch64FloatTrapCondition

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

#
AArch64FloatUnary

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

#
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

#
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
)
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
)

#
AArch64IntBinary

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

#
AArch64IntUnary

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

#
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
)

#
AArch64StackObject

pub struct AArch64StackObject {
offset : Int
size : Int
alignment : Int
area_size : Int
area_alignment : Int
} derive(Eq,
Debug
)

#
AArch64StackObject::new

fn AArch64StackObject::new(offset : Int, size : Int, alignment : Int, area_size : Int, area_alignment : Int) -> AArch64StackObject

#
AArch64VectorIntBinary

pub(all) enum AArch64VectorIntBinary {
Add
Sub
Mul
AverageUnsigned
Min(
Signedness
)
Max(
Signedness
)
SaturatingAdd(
Signedness
)
SaturatingSub(
Signedness
)
ExtendMultiply(
VectorHalf
,
Signedness
)
Dot16To32Signed
Q15MultiplyRoundedSaturating
} derive(Eq,
Debug
)

#
AArch64VectorIntUnary

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

#
AArch64VectorPredicate

pub(all) enum AArch64VectorPredicate {
AnyTrue
AllTrue(
VectorLane
)
BitMask(
VectorLane
)
} derive(Eq,
Debug
)

#
CallArgumentLocation

type CallArgumentLocation derive(Eq,
Debug
)

#
CallLayout

type CallLayout derive(Eq,
Debug
)

#
CallResultLocation

type CallResultLocation derive(Eq,
Debug
)

#
GprWidth

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

#
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
)

#
LoweringContext

pub struct LoweringContext {
// private fields
}

#
LoweringContext::new

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

#
LoweringContext::with_environment_field

fn LoweringContext::with_environment_field(self : LoweringContext, field :
EnvironmentField
, offsets : Array[Int]) -> LoweringContext

#
compile

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.

#
verify_allocation

#
verify_vcode

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io