Path: blob/main/winch/codegen/src/isa/aarch64/regs.rs
1692 views
//! AArch64 register definition.12use crate::isa::reg::Reg;3use crate::regset::RegBitSet;4use regalloc2::{PReg, RegClass};56/// FPR index bound.7const MAX_FPR: u32 = 32;8/// FPR index bound.9const MAX_GPR: u32 = 32;1011/// Construct a X-register from an index.12pub(crate) const fn xreg(num: u8) -> Reg {13assert!((num as u32) < MAX_GPR);14Reg::new(PReg::new(num as usize, RegClass::Int))15}1617/// Construct a V-register from an index.18pub(crate) const fn vreg(num: u8) -> Reg {19assert!((num as u32) < MAX_FPR);20Reg::new(PReg::new(num as usize, RegClass::Float))21}2223/// Scratch register.24/// Intra-procedure-call corruptible register.25pub(crate) const fn ip0() -> Reg {26xreg(16)27}2829// Alias to register v31.30const fn float_scratch() -> Reg {31vreg(31)32}3334/// Scratch register.35/// Intra-procedure-call corruptible register.36pub(crate) const fn ip1() -> Reg {37xreg(17)38}3940/// Register used to carry platform state.41const fn platform() -> Reg {42xreg(18)43}4445/// Frame pointer register.46pub(crate) const fn fp() -> Reg {47xreg(29)48}4950/// Link register for function calls.51pub(crate) const fn lr() -> Reg {52xreg(30)53}5455/// Zero register.56pub(crate) const fn zero() -> Reg {57xreg(31)58}5960/// The VM context register.61pub(crate) const fn vmctx() -> Reg {62xreg(9)63}6465/// Stack pointer register.66///67/// In aarch64 the zero and stack pointer registers are contextually68/// different but have the same hardware encoding; to differentiate69/// them, we are following Cranelift's encoding and representing it as70/// 31 + 32. Ref:71/// https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/codegen/src/isa/aarch64/inst/regs.rs#L7072pub(crate) const fn sp() -> Reg {73Reg::new(PReg::new(31 + 32, RegClass::Int))74}7576/// Shadow stack pointer register.77///78/// The shadow stack pointer (SSP) is used as the base for memory addressing79/// to workaround Aarch64's constraint on the stack pointer 16-byte80/// alignment for memory addressing. This allows word-size loads and81/// stores. It's always assumed that the real stack pointer (SP) is82/// 16-byte unaligned; the only exceptions to this assumption are:83///84/// * The function prologue and epilogue in which we use SP85/// for addressing, assuming that the 16-byte alignment is respected.86/// * Call sites, in which the code generation process explicitly ensures that87/// the stack pointer is 16-byte aligned.88/// * Code that could result in signal handling, like loads/stores.89///90/// SSP is utilized for space allocation. After each allocation, its value is91/// copied to SP, ensuring that SP accurately reflects the allocated space.92/// Accessing memory below SP may lead to undefined behavior, as this memory can93/// be overwritten by interrupts and signal handlers.94///95/// This approach requires copying the value of SSP into SP every time SSP96/// changes, more explicitly, this happens at three main locations:97///98/// 1. After space is allocated, to respect the requirement of avoiding99/// addressing space below SP.100/// 2. At function epilogue.101/// 3. After explicit SP is emitted (code that could result in signal handling).102///103/// +-----------+ Prologue:104/// | | * Save SSP (callee-saved)105/// +-----------+----- * SP at function entry (after prologue, slots for FP and LR)106/// | | * Copy the value of SP to SSP107/// | |108/// +-----------+----- SSP after reserving stack space for locals and arguments109/// | | Copy the value of SSP to SP110/// | |111/// +-----------+----- SSP after a push112/// | | Copy the value of SSP to SP113/// | |114/// | |115/// | |116/// | | Epilogue:117/// | | * Copy SSP to SP118/// +-----------+----- * Restore SSP (callee-saved)119/// +-----------+120///121/// In summary, the following invariants must be respected:122///123/// * SSP is considered primary, and must be used to allocate and deallocate124/// stack space(e.g. push, pop). This operation must always be followed by125/// a copy of SSP to SP.126/// * SP must never be used to address memory except when we are certain that127/// the required alignment is respected (e.g. during the prologue and epilogue)128/// * SP must be explicitly aligned when code could result in signal handling.129/// * The value of SP is copied to SSP when entering a function.130/// * The value of SSP doesn't change between131/// function calls (as it's callee saved), compliant with132/// Aarch64's ABI.133/// * SSP is not available during register allocation.134pub(crate) const fn shadow_sp() -> Reg {135xreg(28)136}137138/// Bitmask for non-allocatable GPR.139const NON_ALLOCATABLE_GPR: u32 = (1 << ip0().hw_enc())140| (1 << ip1().hw_enc())141| (1 << platform().hw_enc())142| (1 << fp().hw_enc())143| (1 << lr().hw_enc())144| (1 << zero().hw_enc())145| (1 << shadow_sp().hw_enc())146| (1 << vmctx().hw_enc());147/// Bitmask to represent the available general purpose registers.148const ALLOCATABLE_GPR: u32 = u32::MAX & !NON_ALLOCATABLE_GPR;149150/// Bitmask for non-allocatable FPR.151/// All FPRs are allocatable, v0..=v7 are generally used for params and results.152153const NON_ALLOCATABLE_FPR: u32 = 1 << float_scratch().hw_enc();154/// Bitmask to represent the available floating point registers.155const ALLOCATABLE_FPR: u32 = u32::MAX & !NON_ALLOCATABLE_FPR;156157/// Allocatable scratch general purpose registers.158const ALLOCATABLE_SCRATCH_GPR: u32 = (1 << ip0().hw_enc()) | (1 << ip1().hw_enc());159/// Non-allocatable scratch general purpose registers.160const NON_ALLOCATABLE_SCRATCH_GPR: u32 = u32::MAX & !ALLOCATABLE_SCRATCH_GPR;161162const ALLOCATABLE_SCRATCH_FPR: u32 = 1 << float_scratch().hw_enc();163/// Non-allocatable scratch general purpose registers.164const NON_ALLOCATABLE_SCRATCH_FPR: u32 = u32::MAX & !ALLOCATABLE_SCRATCH_FPR;165166/// Bitset for allocatable general purpose registers.167pub fn gpr_bit_set() -> RegBitSet {168RegBitSet::int(169ALLOCATABLE_GPR.into(),170NON_ALLOCATABLE_GPR.into(),171usize::try_from(MAX_GPR).unwrap(),172)173}174175/// Bitset for allocatable floating point registers.176pub fn fpr_bit_set() -> RegBitSet {177RegBitSet::float(178ALLOCATABLE_FPR.into(),179NON_ALLOCATABLE_FPR.into(),180usize::try_from(MAX_FPR).unwrap(),181)182}183184/// Bitset for allocatable scratch general purpose registers.185pub fn scratch_gpr_bitset() -> RegBitSet {186RegBitSet::int(187ALLOCATABLE_SCRATCH_GPR.into(),188NON_ALLOCATABLE_SCRATCH_GPR.into(),189usize::try_from(MAX_GPR).unwrap(),190)191}192193/// Bitset for allocatable scratch floating point registers.194pub fn scratch_fpr_bitset() -> RegBitSet {195RegBitSet::float(196ALLOCATABLE_SCRATCH_FPR.into(),197NON_ALLOCATABLE_SCRATCH_FPR.into(),198usize::try_from(MAX_FPR).unwrap(),199)200}201202203