Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/src/api.rs
3050 views
1
//! Contains traits that a user of this assembler must implement.
2
3
use crate::gpr;
4
use crate::xmm;
5
use crate::{Amode, DeferredTarget, GprMem, XmmMem};
6
use alloc::string::String;
7
use alloc::vec::Vec;
8
use core::fmt;
9
use core::num::NonZeroU8;
10
11
/// Describe how an instruction is emitted into a code buffer.
12
pub trait CodeSink {
13
/// Add 1 byte to the code section.
14
fn put1(&mut self, _: u8);
15
16
/// Add 2 bytes to the code section.
17
fn put2(&mut self, _: u16);
18
19
/// Add 4 bytes to the code section.
20
fn put4(&mut self, _: u32);
21
22
/// Add 8 bytes to the code section.
23
fn put8(&mut self, _: u64);
24
25
/// Inform the code buffer of a possible trap at the current location;
26
/// required for assembling memory accesses.
27
fn add_trap(&mut self, code: TrapCode);
28
29
/// Inform the code buffer that a use of `target` is about to happen at the
30
/// current offset.
31
///
32
/// After this method is called the bytes of the target are then expected to
33
/// be placed using one of the above `put*` methods.
34
fn use_target(&mut self, target: DeferredTarget);
35
36
/// Resolves a `KnownOffset` value to the actual signed offset.
37
fn known_offset(&self, offset: KnownOffset) -> i32;
38
}
39
40
/// Provide a convenient implementation for testing.
41
impl CodeSink for Vec<u8> {
42
fn put1(&mut self, v: u8) {
43
self.extend_from_slice(&[v]);
44
}
45
46
fn put2(&mut self, v: u16) {
47
self.extend_from_slice(&v.to_le_bytes());
48
}
49
50
fn put4(&mut self, v: u32) {
51
self.extend_from_slice(&v.to_le_bytes());
52
}
53
54
fn put8(&mut self, v: u64) {
55
self.extend_from_slice(&v.to_le_bytes());
56
}
57
58
fn add_trap(&mut self, _: TrapCode) {}
59
60
fn use_target(&mut self, _: DeferredTarget) {}
61
62
fn known_offset(&self, offset: KnownOffset) -> i32 {
63
panic!("unknown offset {offset:?}")
64
}
65
}
66
67
/// Wrap [`CodeSink`]-specific labels.
68
#[derive(Debug, Copy, Clone, PartialEq)]
69
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
70
pub struct Label(pub u32);
71
72
/// Wrap [`CodeSink`]-specific constant keys.
73
#[derive(Debug, Copy, Clone, PartialEq)]
74
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
75
pub struct Constant(pub u32);
76
77
/// Wrap [`CodeSink`]-specific trap codes.
78
#[derive(Debug, Clone, Copy, PartialEq)]
79
#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
80
pub struct TrapCode(pub NonZeroU8);
81
82
impl fmt::Display for TrapCode {
83
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84
write!(f, "trap={}", self.0)
85
}
86
}
87
88
/// A `KnownOffset` is a unique identifier for a specific offset known only at
89
/// emission time.
90
pub type KnownOffset = u8;
91
92
/// A type set fixing the register types used in the assembler.
93
///
94
/// This assembler is parameterizable over register types; this allows the
95
/// assembler users (e.g., Cranelift) to define their own register types
96
/// independent of this crate.
97
pub trait Registers {
98
/// An x64 general purpose register that may be read.
99
type ReadGpr: AsReg;
100
101
/// An x64 general purpose register that may be read and written.
102
type ReadWriteGpr: AsReg;
103
104
/// An x64 general purpose register that may be written.
105
type WriteGpr: AsReg;
106
107
/// An x64 SSE register that may be read.
108
type ReadXmm: AsReg;
109
110
/// An x64 SSE register that may be read and written.
111
type ReadWriteXmm: AsReg;
112
113
/// An x64 SSE register that may be written.
114
type WriteXmm: AsReg;
115
}
116
117
/// Describe how to interact with an external register type.
118
pub trait AsReg: Copy + Clone + core::fmt::Debug + PartialEq {
119
/// Create a register from its hardware encoding.
120
///
121
/// This is primarily useful for fuzzing, though it is also useful for
122
/// generating fixed registers.
123
fn new(enc: u8) -> Self;
124
125
/// Return the register's hardware encoding; e.g., `0` for `%rax`.
126
fn enc(&self) -> u8;
127
128
/// Return the register name.
129
fn to_string(&self, size: Option<gpr::Size>) -> String {
130
match size {
131
Some(size) => gpr::enc::to_string(self.enc(), size).into(),
132
None => xmm::enc::to_string(self.enc()).into(),
133
}
134
}
135
}
136
137
/// Provide a convenient implementation for testing.
138
impl AsReg for u8 {
139
fn new(enc: u8) -> Self {
140
enc
141
}
142
fn enc(&self) -> u8 {
143
*self
144
}
145
}
146
147
/// Describe a visitor for the register operands of an instruction.
148
///
149
/// Due to how Cranelift's register allocation works, we allow the visitor to
150
/// modify the register operands in place. This allows Cranelift to convert
151
/// virtual registers (`[128..N)`) to physical registers (`[0..16)`) without
152
/// re-allocating the entire instruction object.
153
pub trait RegisterVisitor<R: Registers> {
154
/// Visit a read-only register.
155
fn read_gpr(&mut self, reg: &mut R::ReadGpr);
156
/// Visit a read-write register.
157
fn read_write_gpr(&mut self, reg: &mut R::ReadWriteGpr);
158
/// Visit a write-only register.
159
fn write_gpr(&mut self, reg: &mut R::WriteGpr);
160
161
/// Visit a read-only fixed register; this register can be modified in-place
162
/// but must emit as the hardware encoding `enc`.
163
fn fixed_read_gpr(&mut self, reg: &mut R::ReadGpr, enc: u8);
164
/// Visit a read-write fixed register; this register can be modified
165
/// in-place but must emit as the hardware encoding `enc`.
166
fn fixed_read_write_gpr(&mut self, reg: &mut R::ReadWriteGpr, enc: u8);
167
/// Visit a write-only fixed register; this register can be modified
168
/// in-place but must emit as the hardware encoding `enc`.
169
fn fixed_write_gpr(&mut self, reg: &mut R::WriteGpr, enc: u8);
170
171
/// Visit a read-only SSE register.
172
fn read_xmm(&mut self, reg: &mut R::ReadXmm);
173
/// Visit a read-write SSE register.
174
fn read_write_xmm(&mut self, reg: &mut R::ReadWriteXmm);
175
/// Visit a write-only SSE register.
176
fn write_xmm(&mut self, reg: &mut R::WriteXmm);
177
178
/// Visit a read-only fixed SSE register; this register can be modified
179
/// in-place but must emit as the hardware encoding `enc`.
180
fn fixed_read_xmm(&mut self, reg: &mut R::ReadXmm, enc: u8);
181
/// Visit a read-write fixed SSE register; this register can be modified
182
/// in-place but must emit as the hardware encoding `enc`.
183
fn fixed_read_write_xmm(&mut self, reg: &mut R::ReadWriteXmm, enc: u8);
184
/// Visit a read-only fixed SSE register; this register can be modified
185
/// in-place but must emit as the hardware encoding `enc`.
186
fn fixed_write_xmm(&mut self, reg: &mut R::WriteXmm, enc: u8);
187
188
/// Visit the registers in an [`Amode`].
189
///
190
/// This is helpful for generated code: it allows capturing the `R::ReadGpr`
191
/// type (which an `Amode` method cannot) and simplifies the code to be
192
/// generated.
193
fn read_amode(&mut self, amode: &mut Amode<R::ReadGpr>) {
194
match amode {
195
Amode::ImmReg { base, .. } => {
196
self.read_gpr(base);
197
}
198
Amode::ImmRegRegShift { base, index, .. } => {
199
self.read_gpr(base);
200
self.read_gpr(index.as_mut());
201
}
202
Amode::RipRelative { .. } => {}
203
}
204
}
205
206
/// Helper method to handle a read/write [`GprMem`] operand.
207
fn read_write_gpr_mem(&mut self, op: &mut GprMem<R::ReadWriteGpr, R::ReadGpr>) {
208
match op {
209
GprMem::Gpr(r) => self.read_write_gpr(r),
210
GprMem::Mem(m) => self.read_amode(m),
211
}
212
}
213
214
/// Helper method to handle a write [`GprMem`] operand.
215
fn write_gpr_mem(&mut self, op: &mut GprMem<R::WriteGpr, R::ReadGpr>) {
216
match op {
217
GprMem::Gpr(r) => self.write_gpr(r),
218
GprMem::Mem(m) => self.read_amode(m),
219
}
220
}
221
222
/// Helper method to handle a read-only [`GprMem`] operand.
223
fn read_gpr_mem(&mut self, op: &mut GprMem<R::ReadGpr, R::ReadGpr>) {
224
match op {
225
GprMem::Gpr(r) => self.read_gpr(r),
226
GprMem::Mem(m) => self.read_amode(m),
227
}
228
}
229
230
/// Helper method to handle a read-only [`XmmMem`] operand.
231
fn read_xmm_mem(&mut self, op: &mut XmmMem<R::ReadXmm, R::ReadGpr>) {
232
match op {
233
XmmMem::Xmm(r) => self.read_xmm(r),
234
XmmMem::Mem(m) => self.read_amode(m),
235
}
236
}
237
238
/// Helper method to handle a write [`XmmMem`] operand.
239
fn write_xmm_mem(&mut self, op: &mut XmmMem<R::WriteXmm, R::ReadGpr>) {
240
match op {
241
XmmMem::Xmm(r) => self.write_xmm(r),
242
XmmMem::Mem(m) => self.read_amode(m),
243
}
244
}
245
}
246
247