Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/winch/codegen/src/isa/aarch64/address.rs
1692 views
1
//! Aarch64 addressing mode.
2
3
use anyhow::{Context, Result, anyhow};
4
use cranelift_codegen::VCodeConstant;
5
use cranelift_codegen::{
6
ir::types,
7
isa::aarch64::inst::{AMode, PairAMode, SImm7Scaled, SImm9},
8
};
9
10
use super::regs;
11
use crate::reg::Reg;
12
13
/// Aarch64 indexing mode.
14
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
15
pub(crate) enum Indexing {
16
/// Pre-indexed.
17
Pre,
18
/// Post-indexed.
19
Post,
20
}
21
22
/// Memory address representation.
23
#[derive(Debug, Copy, Clone)]
24
pub(crate) enum Address {
25
/// Base register with an arbitrary offset. Potentially gets
26
/// lowered into multiple instructions during code emission
27
/// depending on the offset.
28
Offset {
29
/// Base register.
30
base: Reg,
31
/// Offset.
32
offset: i64,
33
},
34
/// Specialized indexed register and offset variant using
35
/// the stack pointer.
36
IndexedSPOffset {
37
/// Offset.
38
offset: i64,
39
/// Indexing mode.
40
indexing: Indexing,
41
},
42
/// Address of a constant in the constant pool.
43
Const(VCodeConstant),
44
}
45
46
impl Address {
47
/// Create a pre-indexed addressing mode from the stack pointer.
48
pub fn pre_indexed_from_sp(offset: i64) -> Self {
49
Self::IndexedSPOffset {
50
offset,
51
indexing: Indexing::Pre,
52
}
53
}
54
55
/// Create a post-indexed addressing mode from the stack pointer.
56
pub fn post_indexed_from_sp(offset: i64) -> Self {
57
Self::IndexedSPOffset {
58
offset,
59
indexing: Indexing::Post,
60
}
61
}
62
63
/// Create an offset addressing mode with
64
/// the shadow stack pointer register
65
/// as a base.
66
pub fn from_shadow_sp(offset: i64) -> Self {
67
Self::Offset {
68
base: regs::shadow_sp(),
69
offset,
70
}
71
}
72
73
/// Create register and arbitrary offset addressing mode.
74
pub fn offset(base: Reg, offset: i64) -> Self {
75
// This exists to enforce the sp vs shadow_sp invariant, the
76
// sp generally should not be used as a base register in an
77
// address. In the cases where its usage is required and where
78
// we are sure that it's 16-byte aligned, the address should
79
// be constructed via the `Self::pre_indexed_sp` and
80
// Self::post_indexed_sp functions.
81
// For more details around the stack pointer and shadow stack
82
// pointer see the docs at regs::shadow_sp().
83
assert!(
84
base != regs::sp(),
85
"stack pointer not allowed in arbitrary offset addressing mode"
86
);
87
Self::Offset { base, offset }
88
}
89
90
/// Create an address for a constant.
91
pub fn constant(data: VCodeConstant) -> Self {
92
Self::Const(data)
93
}
94
95
/// Returns the register base and immediate offset of the given [`Address`].
96
///
97
/// # Panics
98
/// This function panics if the [`Address`] is not [`Address::Offset`].
99
pub fn unwrap_offset(&self) -> (Reg, i64) {
100
match self {
101
Self::Offset { base, offset } => (*base, *offset),
102
_ => panic!("Expected register and offset addressing mode"),
103
}
104
}
105
}
106
107
// Conversions between `winch-codegen`'s addressing mode representation
108
// and `cranelift-codegen`s addressing mode representation for aarch64.
109
110
impl TryFrom<Address> for PairAMode {
111
type Error = anyhow::Error;
112
113
fn try_from(addr: Address) -> Result<Self> {
114
use Address::*;
115
use Indexing::*;
116
117
match addr {
118
IndexedSPOffset { offset, indexing } => {
119
let simm7 = SImm7Scaled::maybe_from_i64(offset, types::I64).with_context(|| {
120
format!("Failed to convert {offset} to signed scaled 7 bit offset")
121
})?;
122
123
if indexing == Pre {
124
Ok(PairAMode::SPPreIndexed { simm7 })
125
} else {
126
Ok(PairAMode::SPPostIndexed { simm7 })
127
}
128
}
129
other => Err(anyhow!(
130
"Could not convert {:?} to addressing mode for register pairs",
131
other
132
)),
133
}
134
}
135
}
136
137
impl TryFrom<Address> for AMode {
138
type Error = anyhow::Error;
139
140
fn try_from(addr: Address) -> Result<Self> {
141
use Address::*;
142
use Indexing::*;
143
144
match addr {
145
IndexedSPOffset { offset, indexing } => {
146
let simm9 = SImm9::maybe_from_i64(offset).ok_or_else(|| {
147
// TODO: non-string error
148
anyhow!("Failed to convert {} to signed 9-bit offset", offset)
149
})?;
150
151
if indexing == Pre {
152
Ok(AMode::SPPreIndexed { simm9 })
153
} else {
154
Ok(AMode::SPPostIndexed { simm9 })
155
}
156
}
157
Offset { base, offset } => Ok(AMode::RegOffset {
158
rn: base.into(),
159
off: offset,
160
}),
161
Const(data) => Ok(AMode::Const { addr: data }),
162
}
163
}
164
}
165
166