1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//! AArch64 register definition.
use crateReg;
use ;
/// FPR index bound.
pub const MAX_FPR: u32 = 32;
/// FPR index bound.
pub const MAX_GPR: u32 = 32;
/// Construct a X-register from an index.
pub const
/// Construct a V-register from an index.
pub const
/// Scratch register.
/// Intra-procedure-call corruptible register.
pub const
/// Alias to the IP0 register.
pub const
// Alias to register v31.
pub const
/// Scratch register.
/// Intra-procedure-call corruptible register.
pub const
/// Register used to carry platform state.
const
/// Frame pointer register.
pub const
/// Link register for function calls.
pub const
/// Zero register.
pub const
/// The VM context register.
pub const
/// Stack pointer register.
///
/// In aarch64 the zero and stack pointer registers are contextually
/// different but have the same hardware encoding; to differentiate
/// them, we are following Cranelift's encoding and representing it as
/// 31 + 32. Ref:
/// https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/codegen/src/isa/aarch64/inst/regs.rs#L70
pub const
/// Shadow stack pointer register.
///
/// The shadow stack pointer is used as the base for memory addressing
/// to workaround Aarch64's constraint on the stack pointer 16-byte
/// alignment for memory addressing. This allows word-size loads and
/// stores. It's always assumed that the real stack pointer is
/// 16-byte unaligned; the only exceptions to this assumption are the function
/// prologue and epilogue in which we use the real stack pointer for
/// addressing, assuming that the 16-byte alignment is respected.
///
/// The fact that the shadow stack pointer is used for memory
/// addressing, doesn't change the meaning of the real stack pointer,
/// which should always be used to allocate and deallocate stack
/// space. The real stack pointer is always treated as "primary".
/// Throughout the code generation any change to the stack pointer is
/// reflected in the shadow stack pointer via the
/// [MacroAssembler::move_sp_to_shadow_sp] function.
///
/// This approach, requires copying the real stack pointer value into
/// x28 every time the real stack pointer moves, which involves
/// emitting one more instruction. For example, this is generally how
/// the real stack pointer and x28 will look like during a function:
///
/// +-----------+
/// | | Save x28 (callee-saved)
/// +-----------+----- SP at function entry (after epilogue, slots for FP and LR)
/// | | Copy the value of SP to x28
/// | |
/// +-----------+----- SP after reserving stack space for locals and arguments
/// | | Copy the value of SP to x28
/// | |
/// +-----------+----- SP after a push
/// | | Copy the value of SP to x28 (similar after a pop)
/// | |
/// | |
/// | |
/// | |
/// +-----------+----- At epilogue restore x28 (callee-saved)
/// +-----------+
///
/// In summary, the following invariants must be respected:
///
/// * The real stack pointer is always primary, and must be used to
/// allocate and deallocate stack space(e.g. push, pop). This
/// operation must always be followed by a copy of the real stack
/// pointer to x28.
/// * The real stack pointer must never be used to
/// address memory except when we are certain that the required
/// alignment is respected (e.g. during the prologue and epilogue)
/// * The value of the real stack pointer is copied to x28 when
/// entering a function.
/// * The value of x28 doesn't change between
/// function calls (as it's callee saved), compliant with
/// Aarch64's ABI.
/// * x28 is not available during register allocation.
/// * Since the real stack pointer is always primary, there's no need
/// to copy the shadow stack pointer into the real stack
/// pointer. The copy is only done SP -> Shadow SP direction.
pub const
/// Bitmask for non-allocatable GPR.
pub const NON_ALLOCATABLE_GPR: u32 =
|
|
|
|
|
|
| ;
/// Bitmask to represent the available general purpose registers.
pub const ALL_GPR: u32 = u32MAX & !NON_ALLOCATABLE_GPR;
/// Bitmask for non-allocatable FPR.
/// All FPRs are allocatable, v0..=v7 are generally used for params and results.
pub const NON_ALLOCATABLE_FPR: u32 = 1 << float_scratch.hw_enc;
/// Bitmask to represent the available floating point registers.
pub const ALL_FPR: u32 = u32MAX & !NON_ALLOCATABLE_FPR;