Path: blob/main/cranelift/codegen/src/isa/aarch64/inst/regs.rs
1693 views
//! AArch64 ISA definitions: registers.12use crate::isa::aarch64::inst::OperandSize;3use crate::isa::aarch64::inst::ScalarSize;4use crate::isa::aarch64::inst::VectorSize;5use crate::machinst::RealReg;6use crate::machinst::{Reg, RegClass, Writable};7use regalloc2::PReg;8use regalloc2::VReg;910use std::string::{String, ToString};1112//=============================================================================13// Registers, the Universe thereof, and printing1415/// The pinned register on this architecture.16/// It must be the same as Spidermonkey's HeapReg, as found in this file.17/// https://searchfox.org/mozilla-central/source/js/src/jit/arm64/Assembler-arm64.h#10318pub const PINNED_REG: u8 = 21;1920/// Get a reference to an X-register (integer register). Do not use21/// this for xsp / xzr; we have two special registers for those.22pub const fn xreg(num: u8) -> Reg {23Reg::from_real_reg(xreg_preg(num))24}2526/// Get the given X-register as a PReg.27pub(crate) const fn xreg_preg(num: u8) -> PReg {28assert!(num < 31);29PReg::new(num as usize, RegClass::Int)30}3132/// Get a writable reference to an X-register.33pub fn writable_xreg(num: u8) -> Writable<Reg> {34Writable::from_reg(xreg(num))35}3637/// Get a reference to a V-register (vector/FP register).38pub fn vreg(num: u8) -> Reg {39Reg::from(vreg_preg(num))40}4142/// Get the given V-register as a PReg.43pub(crate) const fn vreg_preg(num: u8) -> PReg {44assert!(num < 32);45PReg::new(num as usize, RegClass::Float)46}4748/// Get a writable reference to a V-register.49#[cfg(test)] // Used only in test code.50pub fn writable_vreg(num: u8) -> Writable<Reg> {51Writable::from_reg(vreg(num))52}5354/// Get a reference to the zero-register.55pub fn zero_reg() -> Reg {56let preg = PReg::new(31, RegClass::Int);57Reg::from(VReg::new(preg.index(), RegClass::Int))58}5960/// Get a writable reference to the zero-register (this discards a result).61pub fn writable_zero_reg() -> Writable<Reg> {62Writable::from_reg(zero_reg())63}6465/// Get a reference to the stack-pointer register.66pub fn stack_reg() -> Reg {67// XSP (stack) and XZR (zero) are logically different registers68// which have the same hardware encoding, and whose meaning, in69// real aarch64 instructions, is context-dependent. For extra70// correctness assurances and for correct printing, we make them71// be two different real registers from a regalloc perspective.72//73// We represent XZR as if it were xreg(31); XSP is xreg(31 +74// 32). The PReg bit-packing allows 6 bits (64 registers) so we75// make use of this extra space to distinguish xzr and xsp. We76// mask off the 6th bit (hw_enc & 31) to get the actual hardware77// register encoding.78let preg = PReg::new(31 + 32, RegClass::Int);79Reg::from(VReg::new(preg.index(), RegClass::Int))80}8182/// Get a writable reference to the stack-pointer register.83pub fn writable_stack_reg() -> Writable<Reg> {84Writable::from_reg(stack_reg())85}8687/// Get a reference to the link register (x30).88pub fn link_reg() -> Reg {89xreg(30)90}9192/// Get a reference to the pinned register (x21).93pub fn pinned_reg() -> Reg {94xreg(PINNED_REG)95}9697/// Get a writable reference to the link register.98pub fn writable_link_reg() -> Writable<Reg> {99Writable::from_reg(link_reg())100}101102/// Get a reference to the frame pointer (x29).103pub fn fp_reg() -> Reg {104xreg(29)105}106107/// Get a writable reference to the frame pointer.108pub fn writable_fp_reg() -> Writable<Reg> {109Writable::from_reg(fp_reg())110}111112/// Get a reference to the first temporary, sometimes "spill temporary", register. This register is113/// used to compute the address of a spill slot when a direct offset addressing mode from FP is not114/// sufficient (+/- 2^11 words). We exclude this register from regalloc and reserve it for this115/// purpose for simplicity; otherwise we need a multi-stage analysis where we first determine how116/// many spill slots we have, then perhaps remove the reg from the pool and recompute regalloc.117///118/// We use x16 for this (aka IP0 in the AArch64 ABI) because it's a scratch register but is119/// slightly special (used for linker veneers). We're free to use it as long as we don't expect it120/// to live through call instructions.121pub fn spilltmp_reg() -> Reg {122xreg(16)123}124125/// Get a writable reference to the spilltmp reg.126pub fn writable_spilltmp_reg() -> Writable<Reg> {127Writable::from_reg(spilltmp_reg())128}129130/// Get a reference to the second temp register. We need this in some edge cases131/// where we need both the spilltmp and another temporary.132///133/// We use x17 (aka IP1), the other "interprocedural"/linker-veneer scratch reg that is134/// free to use otherwise.135pub fn tmp2_reg() -> Reg {136xreg(17)137}138139/// Get a writable reference to the tmp2 reg.140pub fn writable_tmp2_reg() -> Writable<Reg> {141Writable::from_reg(tmp2_reg())142}143144// PrettyPrint cannot be implemented for Reg; we need to invoke145// backend-specific functions from higher level (inst, arg, ...)146// types.147148fn show_ireg(reg: RealReg) -> String {149match reg.hw_enc() {15029 => "fp".to_string(),15130 => "lr".to_string(),15231 => "xzr".to_string(),15363 => "sp".to_string(),154x => {155debug_assert!(x < 29);156format!("x{x}")157}158}159}160161fn show_vreg(reg: RealReg) -> String {162format!("v{}", reg.hw_enc() & 31)163}164165fn show_reg(reg: Reg) -> String {166if let Some(rreg) = reg.to_real_reg() {167match rreg.class() {168RegClass::Int => show_ireg(rreg),169RegClass::Float => show_vreg(rreg),170RegClass::Vector => unreachable!(),171}172} else {173format!("%{reg:?}")174}175}176177pub fn pretty_print_reg(reg: Reg) -> String {178show_reg(reg)179}180181fn show_reg_sized(reg: Reg, size: OperandSize) -> String {182match reg.class() {183RegClass::Int => show_ireg_sized(reg, size),184RegClass::Float => show_reg(reg),185RegClass::Vector => unreachable!(),186}187}188189pub fn pretty_print_reg_sized(reg: Reg, size: OperandSize) -> String {190show_reg_sized(reg, size)191}192193/// If `ireg` denotes an Int-classed reg, make a best-effort attempt to show194/// its name at the 32-bit size.195pub fn show_ireg_sized(reg: Reg, size: OperandSize) -> String {196let mut s = show_reg(reg);197if reg.class() != RegClass::Int || !size.is32() {198// We can't do any better.199return s;200}201202// Change (eg) "x42" into "w42" as appropriate203if reg.class() == RegClass::Int && size.is32() && s.starts_with("x") {204s = "w".to_string() + &s[1..];205}206207s208}209210/// Show a vector register used in a scalar context.211pub fn show_vreg_scalar(reg: Reg, size: ScalarSize) -> String {212let mut s = show_reg(reg);213if reg.class() != RegClass::Float {214// We can't do any better.215return s;216}217218// Change (eg) "v0" into "d0".219if s.starts_with("v") {220let replacement = match size {221ScalarSize::Size8 => "b",222ScalarSize::Size16 => "h",223ScalarSize::Size32 => "s",224ScalarSize::Size64 => "d",225ScalarSize::Size128 => "q",226};227s.replace_range(0..1, replacement);228}229230s231}232233/// Show a vector register.234pub fn show_vreg_vector(reg: Reg, size: VectorSize) -> String {235assert_eq!(RegClass::Float, reg.class());236let mut s = show_reg(reg);237238let suffix = match size {239VectorSize::Size8x8 => ".8b",240VectorSize::Size8x16 => ".16b",241VectorSize::Size16x4 => ".4h",242VectorSize::Size16x8 => ".8h",243VectorSize::Size32x2 => ".2s",244VectorSize::Size32x4 => ".4s",245VectorSize::Size64x2 => ".2d",246};247248s.push_str(suffix);249s250}251252/// Show an indexed vector element.253pub fn show_vreg_element(reg: Reg, idx: u8, size: ScalarSize) -> String {254assert_eq!(RegClass::Float, reg.class());255let s = show_reg(reg);256let suffix = match size {257ScalarSize::Size8 => ".b",258ScalarSize::Size16 => ".h",259ScalarSize::Size32 => ".s",260ScalarSize::Size64 => ".d",261_ => panic!("Unexpected vector element size: {size:?}"),262};263format!("{s}{suffix}[{idx}]")264}265266pub fn pretty_print_ireg(reg: Reg, size: OperandSize) -> String {267show_ireg_sized(reg, size)268}269270pub fn pretty_print_vreg_scalar(reg: Reg, size: ScalarSize) -> String {271show_vreg_scalar(reg, size)272}273274pub fn pretty_print_vreg_vector(reg: Reg, size: VectorSize) -> String {275show_vreg_vector(reg, size)276}277278pub fn pretty_print_vreg_element(reg: Reg, idx: usize, size: ScalarSize) -> String {279show_vreg_element(reg, idx as u8, size)280}281282283