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