///|
// ARM64 (AArch64) target constants, AAPCS64 ABI.
// Ported 1:1 from vendor/qbe/arm64/{all.h, targ.c} (the byte-level
// differential oracle). Register tmp ids are renumbered (QBE-style) instead
// of using the raw machine numbers so that the allocatable ranges stay
// contiguous.
///|
// ARM64 register numbers (as virtual tmp ids; matches C enum Arm64Reg where
// R0 = RXX + 1, so bit 0 of a register mask is always unused).
///|
// General purpose registers x0-x15.
pub const ARM64_R0 : Int = 1
///|
pub const ARM64_R1 : Int = 2
///|
pub const ARM64_R2 : Int = 3
///|
pub const ARM64_R3 : Int = 4
///|
pub const ARM64_R4 : Int = 5
///|
pub const ARM64_R5 : Int = 6
///|
pub const ARM64_R6 : Int = 7
///|
pub const ARM64_R7 : Int = 8
///|
// x8: indirect result location register (aggregate return).
pub const ARM64_R8 : Int = 9
///|
pub const ARM64_R9 : Int = 10
///|
pub const ARM64_R10 : Int = 11
///|
pub const ARM64_R11 : Int = 12
///|
pub const ARM64_R12 : Int = 13
///|
pub const ARM64_R13 : Int = 14
///|
pub const ARM64_R14 : Int = 15
///|
pub const ARM64_R15 : Int = 16
///|
// Intra-procedure call scratch registers (x16/x17). IP1 is globally live.
pub const ARM64_IP0 : Int = 17
///|
pub const ARM64_IP1 : Int = 18
///|
// Platform register x18 (reserved on Apple; globally live here).
pub const ARM64_R18 : Int = 19
///|
// Callee-save general purpose registers x19-x28.
pub const ARM64_R19 : Int = 20
///|
pub const ARM64_R20 : Int = 21
///|
pub const ARM64_R21 : Int = 22
///|
pub const ARM64_R22 : Int = 23
///|
pub const ARM64_R23 : Int = 24
///|
pub const ARM64_R24 : Int = 25
///|
pub const ARM64_R25 : Int = 26
///|
pub const ARM64_R26 : Int = 27
///|
pub const ARM64_R27 : Int = 28
///|
pub const ARM64_R28 : Int = 29
///|
// Frame pointer (x29) — globally live.
pub const ARM64_FP : Int = 30
///|
// Link register (x30) — caller-save on arm64.
pub const ARM64_LR : Int = 31
///|
// Stack pointer (x31) — globally live.
pub const ARM64_SP : Int = 32
///|
// FP caller-save registers v0-v7.
pub const ARM64_V0 : Int = 33
///|
pub const ARM64_V1 : Int = 34
///|
pub const ARM64_V2 : Int = 35
///|
pub const ARM64_V3 : Int = 36
///|
pub const ARM64_V4 : Int = 37
///|
pub const ARM64_V5 : Int = 38
///|
pub const ARM64_V6 : Int = 39
///|
pub const ARM64_V7 : Int = 40
///|
// FP callee-save registers v8-v15 (lower 64 bits only).
pub const ARM64_V8 : Int = 41
///|
pub const ARM64_V9 : Int = 42
///|
pub const ARM64_V10 : Int = 43
///|
pub const ARM64_V11 : Int = 44
///|
pub const ARM64_V12 : Int = 45
///|
pub const ARM64_V13 : Int = 46
///|
pub const ARM64_V14 : Int = 47
///|
pub const ARM64_V15 : Int = 48
///|
// FP caller-save registers v16-v30.
pub const ARM64_V16 : Int = 49
///|
pub const ARM64_V17 : Int = 50
///|
pub const ARM64_V18 : Int = 51
///|
pub const ARM64_V19 : Int = 52
///|
pub const ARM64_V20 : Int = 53
///|
pub const ARM64_V21 : Int = 54
///|
pub const ARM64_V22 : Int = 55
///|
pub const ARM64_V23 : Int = 56
///|
pub const ARM64_V24 : Int = 57
///|
pub const ARM64_V25 : Int = 58
///|
pub const ARM64_V26 : Int = 59
///|
pub const ARM64_V27 : Int = 60
///|
pub const ARM64_V28 : Int = 61
///|
pub const ARM64_V29 : Int = 62
///|
pub const ARM64_V30 : Int = 63
///|
// Tmp0 - first non-register temporary (NBit = 64; V30 < Tmp0 holds).
pub const Arm64Tmp0 : Int = 64
///|
// Number of general purpose registers (R0-SP, matches C NGPR).
pub const Arm64NGPR : Int = 32
///|
// Number of float registers (V0-V30, matches C NFPR).
pub const Arm64NFPR : Int = 31
///|
// Number of caller-save GPRs (R0-R15, IP0, IP1, R18, LR = 20).
pub const Arm64NGPS : Int = 20
///|
// Number of caller-save FPRs (v0-v7 and v16-v30, matches C NFPS).
pub const Arm64NFPS : Int = 23
///|
// Number of callee-save registers (x19-x28 and v8-v15, matches C NCLR).
pub const Arm64NCLR : Int = 18
///|
// Number of globally live registers (FP, SP, R18).
pub const Arm64NRGLOB : Int = 3
///|
// ARM64 caller-save register list (C arm64_rsave in targ.c).
pub let arm64_rsave : Array[Int] = [
ARM64_R0,
ARM64_R1,
ARM64_R2,
ARM64_R3,
ARM64_R4,
ARM64_R5,
ARM64_R6,
ARM64_R7,
ARM64_R8,
ARM64_R9,
ARM64_R10,
ARM64_R11,
ARM64_R12,
ARM64_R13,
ARM64_R14,
ARM64_R15,
ARM64_IP0,
ARM64_IP1,
ARM64_R18,
ARM64_LR,
ARM64_V0,
ARM64_V1,
ARM64_V2,
ARM64_V3,
ARM64_V4,
ARM64_V5,
ARM64_V6,
ARM64_V7,
ARM64_V16,
ARM64_V17,
ARM64_V18,
ARM64_V19,
ARM64_V20,
ARM64_V21,
ARM64_V22,
ARM64_V23,
ARM64_V24,
ARM64_V25,
ARM64_V26,
ARM64_V27,
ARM64_V28,
ARM64_V29,
ARM64_V30,
]
///|
// ARM64 callee-save register list (C arm64_rclob in targ.c).
pub let arm64_rclob : Array[Int] = [
ARM64_R19,
ARM64_R20,
ARM64_R21,
ARM64_R22,
ARM64_R23,
ARM64_R24,
ARM64_R25,
ARM64_R26,
ARM64_R27,
ARM64_R28,
ARM64_V8,
ARM64_V9,
ARM64_V10,
ARM64_V11,
ARM64_V12,
ARM64_V13,
ARM64_V14,
ARM64_V15,
]
///|
// ARM64 globally live registers bitmask (C RGLOB: FP | SP | IP1 | R18).
// These overlap no argument register (C MAKESURE globals_are_not_arguments).
pub fn arm64_rglob_mask() -> UInt64 {
let one : UInt64 = 1
(one << ARM64_FP) |
(one << ARM64_SP) |
(one << ARM64_IP1) |
(one << ARM64_R18)
}
///|
// The registers returned by a call, given its RCall ref
// (C arm64_retregs in abi.c). Returns (bits, ngp, nfpr).
pub fn Ref::arm64_retregs(self : Ref) -> (UInt64, Int, Int) {
let mut b : UInt64 = 0
let v = self.call_val()
let mut ngp = v & 3
let mut nfp = (v >> 2) & 7
while ngp > 0 {
ngp = ngp - 1
b = b | (1UL << (ARM64_R0 + ngp))
}
while nfp > 0 {
nfp = nfp - 1
b = b | (1UL << (ARM64_V0 + nfp))
}
(b, v & 3, (v >> 2) & 7)
}
///|
// The registers used to pass arguments, given an RCall ref
// (C arm64_argregs in abi.c). x8 carries the aggregate-return hidden pointer
// (bit 13).
pub fn Ref::arm64_argregs(self : Ref) -> (UInt64, Int, Int) {
let mut b : UInt64 = 0
let v = self.call_val()
let mut ngp = (v >> 5) & 15
let mut nfp = (v >> 9) & 15
let x8 = (v >> 13) & 1
while ngp > 0 {
ngp = ngp - 1
b = b | (1UL << (ARM64_R0 + ngp))
}
while nfp > 0 {
nfp = nfp - 1
b = b | (1UL << (ARM64_V0 + nfp))
}
if x8 != 0 {
b = b | (1UL << ARM64_R8)
}
(b, ((v >> 5) & 15) + x8, (v >> 9) & 15)
}
///|
// Map ARM64 register number to its asm name (C arm64 reg mapping in emit.c).
// The width variants (w0/d0/s0) are applied by the emitter per class.
pub fn arm64_reg_name(reg : Int) -> String {
match reg {
ARM64_R0 => "x0"
ARM64_R1 => "x1"
ARM64_R2 => "x2"
ARM64_R3 => "x3"
ARM64_R4 => "x4"
ARM64_R5 => "x5"
ARM64_R6 => "x6"
ARM64_R7 => "x7"
ARM64_R8 => "x8"
ARM64_R9 => "x9"
ARM64_R10 => "x10"
ARM64_R11 => "x11"
ARM64_R12 => "x12"
ARM64_R13 => "x13"
ARM64_R14 => "x14"
ARM64_R15 => "x15"
ARM64_IP0 => "x16"
ARM64_IP1 => "x17"
ARM64_R18 => "x18"
ARM64_R19 => "x19"
ARM64_R20 => "x20"
ARM64_R21 => "x21"
ARM64_R22 => "x22"
ARM64_R23 => "x23"
ARM64_R24 => "x24"
ARM64_R25 => "x25"
ARM64_R26 => "x26"
ARM64_R27 => "x27"
ARM64_R28 => "x28"
ARM64_FP => "x29"
ARM64_LR => "x30"
ARM64_SP => "sp"
ARM64_V0 => "v0"
ARM64_V1 => "v1"
ARM64_V2 => "v2"
ARM64_V3 => "v3"
ARM64_V4 => "v4"
ARM64_V5 => "v5"
ARM64_V6 => "v6"
ARM64_V7 => "v7"
ARM64_V8 => "v8"
ARM64_V9 => "v9"
ARM64_V10 => "v10"
ARM64_V11 => "v11"
ARM64_V12 => "v12"
ARM64_V13 => "v13"
ARM64_V14 => "v14"
ARM64_V15 => "v15"
ARM64_V16 => "v16"
ARM64_V17 => "v17"
ARM64_V18 => "v18"
ARM64_V19 => "v19"
ARM64_V20 => "v20"
ARM64_V21 => "v21"
ARM64_V22 => "v22"
ARM64_V23 => "v23"
ARM64_V24 => "v24"
ARM64_V25 => "v25"
ARM64_V26 => "v26"
ARM64_V27 => "v27"
ARM64_V28 => "v28"
ARM64_V29 => "v29"
ARM64_V30 => "v30"
_ => "?"
}
}
///|
// ARM64 pointer size: Kl (64-bit).
pub const Arm64KmIsWide : Int = 1
///|
// ARM64 call return registers: x0/x1 and v0-v3 (C arm64_retregs).
fn arm64_target_retregs(r : Ref) -> (UInt64, Int, Int) {
r.arm64_retregs()
}
///|
// ARM64 call argument registers: x0.. and v0.., x8/x9 flags (C arm64_argregs).
fn arm64_target_argregs(r : Ref) -> (UInt64, Int, Int) {
r.arm64_argregs()
}
///|
// Select the arm64 target (C T_arm64, ELF flavor).
pub fn init_arm64_target() -> Unit {
target_cfg.gpr_base = ARM64_R0
target_cfg.fpr_base = ARM64_V0
target_cfg.ngpr = Arm64NGPR
target_cfg.nfpr = Arm64NFPR
target_cfg.fpr_class_base = ARM64_V0
target_cfg.post_call_gpr = Arm64NGPS
target_cfg.post_call_fpr = Arm64NFPS
target_cfg.rglob_mask = arm64_rglob_mask()
target_cfg.rsave = arm64_rsave
target_cfg.retregs = arm64_target_retregs
target_cfg.argregs = arm64_target_argregs
}