Path: blob/main/winch/codegen/src/isa/aarch64/address.rs
3070 views
//! Aarch64 addressing mode.12use super::regs;3use crate::reg::Reg;4use crate::{Context as _, Result, format_err};5use cranelift_codegen::VCodeConstant;6use cranelift_codegen::{7ir::types,8isa::aarch64::inst::{AMode, PairAMode, SImm7Scaled, SImm9},9};1011/// Aarch64 indexing mode.12#[derive(Copy, Clone, Debug, Eq, PartialEq)]13pub(crate) enum Indexing {14/// Pre-indexed.15Pre,16/// Post-indexed.17Post,18}1920/// Memory address representation.21#[derive(Debug, Copy, Clone)]22pub(crate) enum Address {23/// Base register with an arbitrary offset. Potentially gets24/// lowered into multiple instructions during code emission25/// depending on the offset.26Offset {27/// Base register.28base: Reg,29/// Offset.30offset: i64,31},32/// Specialized indexed register and offset variant using33/// the stack pointer.34IndexedSPOffset {35/// Offset.36offset: i64,37/// Indexing mode.38indexing: Indexing,39},40/// Address of a constant in the constant pool.41Const(VCodeConstant),42}4344impl Address {45/// Create a pre-indexed addressing mode from the stack pointer.46pub fn pre_indexed_from_sp(offset: i64) -> Self {47Self::IndexedSPOffset {48offset,49indexing: Indexing::Pre,50}51}5253/// Create a post-indexed addressing mode from the stack pointer.54pub fn post_indexed_from_sp(offset: i64) -> Self {55Self::IndexedSPOffset {56offset,57indexing: Indexing::Post,58}59}6061/// Create an offset addressing mode with62/// the shadow stack pointer register63/// as a base.64pub fn from_shadow_sp(offset: i64) -> Self {65Self::Offset {66base: regs::shadow_sp(),67offset,68}69}7071/// Create register and arbitrary offset addressing mode.72pub fn offset(base: Reg, offset: i64) -> Self {73// This exists to enforce the sp vs shadow_sp invariant, the74// sp generally should not be used as a base register in an75// address. In the cases where its usage is required and where76// we are sure that it's 16-byte aligned, the address should77// be constructed via the `Self::pre_indexed_sp` and78// Self::post_indexed_sp functions.79// For more details around the stack pointer and shadow stack80// pointer see the docs at regs::shadow_sp().81assert!(82base != regs::sp(),83"stack pointer not allowed in arbitrary offset addressing mode"84);85Self::Offset { base, offset }86}8788/// Create an address for a constant.89pub fn constant(data: VCodeConstant) -> Self {90Self::Const(data)91}9293/// Returns the register base and immediate offset of the given [`Address`].94///95/// # Panics96/// This function panics if the [`Address`] is not [`Address::Offset`].97pub fn unwrap_offset(&self) -> (Reg, i64) {98match self {99Self::Offset { base, offset } => (*base, *offset),100_ => panic!("Expected register and offset addressing mode"),101}102}103}104105// Conversions between `winch-codegen`'s addressing mode representation106// and `cranelift-codegen`s addressing mode representation for aarch64.107108impl TryFrom<Address> for PairAMode {109type Error = crate::Error;110111fn try_from(addr: Address) -> Result<Self> {112use Address::*;113use Indexing::*;114115match addr {116IndexedSPOffset { offset, indexing } => {117let simm7 = SImm7Scaled::maybe_from_i64(offset, types::I64).with_context(|| {118format!("Failed to convert {offset} to signed scaled 7 bit offset")119})?;120121if indexing == Pre {122Ok(PairAMode::SPPreIndexed { simm7 })123} else {124Ok(PairAMode::SPPostIndexed { simm7 })125}126}127other => Err(format_err!(128"Could not convert {other:?} to addressing mode for register pairs"129)),130}131}132}133134impl TryFrom<Address> for AMode {135type Error = crate::Error;136137fn try_from(addr: Address) -> Result<Self> {138use Address::*;139use Indexing::*;140141match addr {142IndexedSPOffset { offset, indexing } => {143let simm9 = SImm9::maybe_from_i64(offset).ok_or_else(|| {144// TODO: non-string error145format_err!("Failed to convert {offset} to signed 9-bit offset")146})?;147148if indexing == Pre {149Ok(AMode::SPPreIndexed { simm9 })150} else {151Ok(AMode::SPPostIndexed { simm9 })152}153}154Offset { base, offset } => Ok(AMode::RegOffset {155rn: base.into(),156off: offset,157}),158Const(data) => Ok(AMode::Const { addr: data }),159}160}161}162163164