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