Path: blob/main/winch/codegen/src/isa/aarch64/address.rs
1692 views
//! Aarch64 addressing mode.12use anyhow::{Context, Result, anyhow};3use cranelift_codegen::VCodeConstant;4use cranelift_codegen::{5ir::types,6isa::aarch64::inst::{AMode, PairAMode, SImm7Scaled, SImm9},7};89use super::regs;10use crate::reg::Reg;1112/// Aarch64 indexing mode.13#[derive(Copy, Clone, Debug, Eq, PartialEq)]14pub(crate) enum Indexing {15/// Pre-indexed.16Pre,17/// Post-indexed.18Post,19}2021/// Memory address representation.22#[derive(Debug, Copy, Clone)]23pub(crate) enum Address {24/// Base register with an arbitrary offset. Potentially gets25/// lowered into multiple instructions during code emission26/// depending on the offset.27Offset {28/// Base register.29base: Reg,30/// Offset.31offset: i64,32},33/// Specialized indexed register and offset variant using34/// the stack pointer.35IndexedSPOffset {36/// Offset.37offset: i64,38/// Indexing mode.39indexing: Indexing,40},41/// Address of a constant in the constant pool.42Const(VCodeConstant),43}4445impl Address {46/// Create a pre-indexed addressing mode from the stack pointer.47pub fn pre_indexed_from_sp(offset: i64) -> Self {48Self::IndexedSPOffset {49offset,50indexing: Indexing::Pre,51}52}5354/// Create a post-indexed addressing mode from the stack pointer.55pub fn post_indexed_from_sp(offset: i64) -> Self {56Self::IndexedSPOffset {57offset,58indexing: Indexing::Post,59}60}6162/// Create an offset addressing mode with63/// the shadow stack pointer register64/// as a base.65pub fn from_shadow_sp(offset: i64) -> Self {66Self::Offset {67base: regs::shadow_sp(),68offset,69}70}7172/// Create register and arbitrary offset addressing mode.73pub fn offset(base: Reg, offset: i64) -> Self {74// This exists to enforce the sp vs shadow_sp invariant, the75// sp generally should not be used as a base register in an76// address. In the cases where its usage is required and where77// we are sure that it's 16-byte aligned, the address should78// be constructed via the `Self::pre_indexed_sp` and79// Self::post_indexed_sp functions.80// For more details around the stack pointer and shadow stack81// pointer see the docs at regs::shadow_sp().82assert!(83base != regs::sp(),84"stack pointer not allowed in arbitrary offset addressing mode"85);86Self::Offset { base, offset }87}8889/// Create an address for a constant.90pub fn constant(data: VCodeConstant) -> Self {91Self::Const(data)92}9394/// Returns the register base and immediate offset of the given [`Address`].95///96/// # Panics97/// This function panics if the [`Address`] is not [`Address::Offset`].98pub fn unwrap_offset(&self) -> (Reg, i64) {99match self {100Self::Offset { base, offset } => (*base, *offset),101_ => panic!("Expected register and offset addressing mode"),102}103}104}105106// Conversions between `winch-codegen`'s addressing mode representation107// and `cranelift-codegen`s addressing mode representation for aarch64.108109impl TryFrom<Address> for PairAMode {110type Error = anyhow::Error;111112fn try_from(addr: Address) -> Result<Self> {113use Address::*;114use Indexing::*;115116match addr {117IndexedSPOffset { offset, indexing } => {118let simm7 = SImm7Scaled::maybe_from_i64(offset, types::I64).with_context(|| {119format!("Failed to convert {offset} to signed scaled 7 bit offset")120})?;121122if indexing == Pre {123Ok(PairAMode::SPPreIndexed { simm7 })124} else {125Ok(PairAMode::SPPostIndexed { simm7 })126}127}128other => Err(anyhow!(129"Could not convert {:?} to addressing mode for register pairs",130other131)),132}133}134}135136impl TryFrom<Address> for AMode {137type Error = anyhow::Error;138139fn try_from(addr: Address) -> Result<Self> {140use Address::*;141use Indexing::*;142143match addr {144IndexedSPOffset { offset, indexing } => {145let simm9 = SImm9::maybe_from_i64(offset).ok_or_else(|| {146// TODO: non-string error147anyhow!("Failed to convert {} to signed 9-bit offset", offset)148})?;149150if indexing == Pre {151Ok(AMode::SPPreIndexed { simm9 })152} else {153Ok(AMode::SPPostIndexed { simm9 })154}155}156Offset { base, offset } => Ok(AMode::RegOffset {157rn: base.into(),158off: offset,159}),160Const(data) => Ok(AMode::Const { addr: data }),161}162}163}164165166