///|
// Target abstraction - corresponds to struct Target and amd64/all.h
///|
// AMD64 register numbers (as virtual tmp ids, matching C enum Amd64Reg)
pub const RXX : Int = 0
///|
pub const RAX : Int = 1
///|
pub const RCX : Int = 2
///|
pub const RDX : Int = 3
///|
pub const RSI : Int = 4
///|
pub const RDI : Int = 5
///|
pub const R8 : Int = 6
///|
pub const R9 : Int = 7
///|
pub const R10 : Int = 8
///|
pub const R11 : Int = 9
///|
pub const RBX : Int = 10
///|
pub const R12 : Int = 11
///|
pub const R13 : Int = 12
///|
pub const R14 : Int = 13
///|
pub const R15 : Int = 14
///|
pub const RBP : Int = 15
///|
pub const RSP : Int = 16
///|
pub const XMM0 : Int = 17
///|
pub const XMM1 : Int = 18
///|
pub const XMM2 : Int = 19
///|
pub const XMM3 : Int = 20
///|
pub const XMM4 : Int = 21
///|
pub const XMM5 : Int = 22
///|
pub const XMM6 : Int = 23
///|
pub const XMM7 : Int = 24
///|
pub const XMM8 : Int = 25
///|
pub const XMM9 : Int = 26
///|
pub const XMM10 : Int = 27
///|
pub const XMM11 : Int = 28
///|
pub const XMM12 : Int = 29
///|
pub const XMM13 : Int = 30
///|
pub const XMM14 : Int = 31
///|
pub const XMM15 : Int = 32
///|
// Tmp0 - first non-register temporary (NBit = 64)
pub const Tmp0 : Int = 64
///|
// Number of general purpose registers
pub const NGPR : Int = RSP - RAX + 1
///|
// Number of float registers
pub const NFPR : Int = XMM14 - XMM0 + 1
///|
// Number of caller-save GPRs (RAX..R11)
pub const NGPS : Int = R11 - RAX + 1
///|
// Number of caller-save FPRs
pub const NFPS : Int = NFPR
///|
// Number of callee-save registers (RBX..R15)
pub const NCLR : Int = R15 - RBX + 1
///|
// Caller-save registers for amd64 sysv (C amd64_sysv_rsave in sysv.c).
// These are the argument/return registers used by retregs/argregs and by
// the spill/rega passes (T.rsave).
pub let rsave : Array[Int] = [
RDI,
RSI,
RDX,
RCX,
R8,
R9,
R10,
R11,
RAX,
XMM0,
XMM1,
XMM2,
XMM3,
XMM4,
XMM5,
XMM6,
XMM7,
XMM8,
XMM9,
XMM10,
XMM11,
XMM12,
XMM13,
XMM14,
]
///|
// Callee-save registers (C amd64_sysv_rclob in sysv.c).
pub let rclob : Array[Int] = [RBX, R12, R13, R14, R15]
///|
// The registers returned by a call, given its RCall ref (C retregs).
// Returns (bits, ngp, nfpr).
#as_free_fn(retregs, deprecated="use `Ref::retregs` instead")
pub fn Ref::retregs(self : Ref) -> (UInt64, Int, Int) {
let mut b : UInt64 = 0
let v = self.call_val()
let ni = v & 3
let nf = (v >> 2) & 3
if ni >= 1 {
b = b | (1UL << RAX)
}
if ni >= 2 {
b = b | (1UL << RDX)
}
if nf >= 1 {
b = b | (1UL << XMM0)
}
if nf >= 2 {
b = b | (1UL << XMM1)
}
(b, ni, nf)
}
///|
// The registers used to pass arguments, given an RCall ref (C argregs).
// Returns (bits, ngp, nfpr).
#as_free_fn(argregs, deprecated="use `Ref::argregs` instead")
pub fn Ref::argregs(self : Ref) -> (UInt64, Int, Int) {
let mut b : UInt64 = 0
let v = self.call_val()
let ni = (v >> 4) & 15
let nf = (v >> 8) & 15
let ra = (v >> 12) & 1
for j in 0.. UInt64 {
let one : UInt64 = 1
(one << RBP) | (one << RSP)
}
///|
// Number of globally live registers
pub const NRGLOB : Int = 2
///|
// Target description - corresponds to C's `struct Target T` (all.h).
// spill/rega are target-agnostic and read the current target through the
// `target_cfg` global, which is selected by `init_amd64_target` /
// `init_rv64_target` before the post-isel passes run.
pub struct TargetCfg {
// First GPR/FPR tmp ids scanned by rega (C T.gpr_base / T.fpr_base).
mut gpr_base : Int
mut fpr_base : Int
// Number of registers scanned by rega/spill (C T.ngpr / T.nfpr).
mut ngpr : Int
mut nfpr : Int
// First FPR id in class-order scans (spill classifies tmp ids).
mut fpr_class_base : Int
// Register limits applied right after a call (C limit2(v, NGPS, NFPS)).
mut post_call_gpr : Int
mut post_call_fpr : Int
// Globally live registers bitmask (C T.rglob).
mut rglob_mask : UInt64
// Caller-save registers (C T.rsave).
mut rsave : Array[Int]
// Call return/argument register mapping (C T.retregs / T.argregs).
mut retregs : (Ref) -> (UInt64, Int, Int)
mut argregs : (Ref) -> (UInt64, Int, Int)
}
///|
// amd64_sysv call return registers (C amd64_sysv retregs).
fn amd64_target_retregs(r : Ref) -> (UInt64, Int, Int) {
let mut b : UInt64 = 0
let v = r.call_val()
let ni = v & 3
let nf = (v >> 2) & 3
if ni >= 1 {
b = b | (1UL << RAX)
}
if ni >= 2 {
b = b | (1UL << RDX)
}
if nf >= 1 {
b = b | (1UL << XMM0)
}
if nf >= 2 {
b = b | (1UL << XMM1)
}
(b, ni, nf)
}
///|
// amd64_sysv call argument registers (C amd64_sysv argregs).
fn amd64_target_argregs(r : Ref) -> (UInt64, Int, Int) {
let mut b : UInt64 = 0
let v = r.call_val()
let ni = (v >> 4) & 15
let nf = (v >> 8) & 15
let ra = (v >> 12) & 1
for j in 0.. TargetCfg {
TargetCfg::{
gpr_base: RAX,
fpr_base: XMM0,
ngpr: NGPR,
nfpr: NFPR,
fpr_class_base: XMM0,
post_call_gpr: NGPS,
post_call_fpr: NFPS,
rglob_mask: rglob_mask(),
rsave,
retregs: amd64_target_retregs,
argregs: amd64_target_argregs,
}
}
///|
// The current target, defaulting to amd64_sysv.
pub let target_cfg : TargetCfg = amd64_target_cfg()
///|
// Select the amd64_sysv target (C init(T_amd64_sysv)).
pub fn init_amd64_target() -> Unit {
let amd = amd64_target_cfg()
target_cfg.gpr_base = amd.gpr_base
target_cfg.fpr_base = amd.fpr_base
target_cfg.ngpr = amd.ngpr
target_cfg.nfpr = amd.nfpr
target_cfg.fpr_class_base = amd.fpr_class_base
target_cfg.post_call_gpr = amd.post_call_gpr
target_cfg.post_call_fpr = amd.post_call_fpr
target_cfg.rglob_mask = amd.rglob_mask
target_cfg.rsave = amd.rsave
target_cfg.retregs = amd.retregs
target_cfg.argregs = amd.argregs
}
///|
// The registers returned by a call on the current target (C T.retregs).
pub fn target_retregs(r : Ref) -> (UInt64, Int, Int) {
(target_cfg.retregs)(r)
}
///|
// The registers used to pass arguments on the current target (C T.argregs).
pub fn target_argregs(r : Ref) -> (UInt64, Int, Int) {
(target_cfg.argregs)(r)
}