cranelift_assembler_x64/api.rs
1//! Contains traits that a user of this assembler must implement.
2
3use crate::gpr;
4use crate::xmm;
5use std::{num::NonZeroU8, ops::Index, vec::Vec};
6
7/// Describe how an instruction is emitted into a code buffer.
8pub trait CodeSink {
9 /// Add 1 byte to the code section.
10 fn put1(&mut self, _: u8);
11
12 /// Add 2 bytes to the code section.
13 fn put2(&mut self, _: u16);
14
15 /// Add 4 bytes to the code section.
16 fn put4(&mut self, _: u32);
17
18 /// Add 8 bytes to the code section.
19 fn put8(&mut self, _: u64);
20
21 /// Inform the code buffer of a possible trap at the current location;
22 /// required for assembling memory accesses.
23 fn add_trap(&mut self, code: TrapCode);
24
25 /// Return the byte offset of the current location in the code buffer;
26 /// required for assembling RIP-relative memory accesses.
27 fn current_offset(&self) -> u32;
28
29 /// Inform the code buffer of a use of `label` at `offset`; required for
30 /// assembling RIP-relative memory accesses.
31 fn use_label_at_offset(&mut self, offset: u32, label: Label);
32
33 /// Return the label for a constant `id`; required for assembling
34 /// RIP-relative memory accesses of constants.
35 fn get_label_for_constant(&mut self, id: Constant) -> Label;
36}
37
38/// Provide a convenient implementation for testing.
39impl 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 current_offset(&self) -> u32 {
59 self.len().try_into().unwrap()
60 }
61
62 fn use_label_at_offset(&mut self, _: u32, _: Label) {}
63
64 fn get_label_for_constant(&mut self, c: Constant) -> Label {
65 Label(c.0)
66 }
67}
68
69/// Wrap [`CodeSink`]-specific labels.
70#[derive(Debug, Clone)]
71#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
72pub struct Label(pub u32);
73
74/// Wrap [`CodeSink`]-specific constant keys.
75#[derive(Debug, Clone)]
76#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
77pub struct Constant(pub u32);
78
79/// Wrap [`CodeSink`]-specific trap codes.
80#[derive(Debug, Clone, Copy)]
81#[cfg_attr(any(test, feature = "fuzz"), derive(arbitrary::Arbitrary))]
82pub struct TrapCode(pub NonZeroU8);
83
84/// A table mapping `KnownOffset` identifiers to their `i32` offset values.
85///
86/// When encoding instructions, Cranelift may not know all of the information
87/// needed to construct an immediate. Specifically, addressing modes that
88/// require knowing the size of the tail arguments or outgoing arguments (see
89/// `SyntheticAmode::finalize`) will not know these sizes until emission.
90///
91/// This table allows up to do a "late" look up of these values by their
92/// `KnownOffset`.
93pub trait KnownOffsetTable: Index<KnownOffset, Output = i32> {}
94impl KnownOffsetTable for Vec<i32> {}
95/// Provide a convenient implementation for testing.
96impl KnownOffsetTable for [i32; 2] {}
97
98/// A `KnownOffset` is a unique identifier for a specific offset known only at
99/// emission time.
100pub type KnownOffset = usize;
101
102/// A type set fixing the register types used in the assembler.
103///
104/// This assembler is parameterizable over register types; this allows the
105/// assembler users (e.g., Cranelift) to define their own register types
106/// independent of this crate.
107pub trait Registers {
108 /// An x64 general purpose register that may be read.
109 type ReadGpr: AsReg;
110
111 /// An x64 general purpose register that may be read and written.
112 type ReadWriteGpr: AsReg;
113
114 /// An x64 SSE register that may be read.
115 type ReadXmm: AsReg;
116
117 /// An x64 SSE register that may be read and written.
118 type ReadWriteXmm: AsReg;
119}
120
121/// Describe how to interact with an external register type.
122pub trait AsReg: Clone + std::fmt::Debug {
123 /// Create a register from its hardware encoding.
124 ///
125 /// This is primarily useful for fuzzing, though it is also useful for
126 /// generating fixed registers.
127 fn new(enc: u8) -> Self;
128
129 /// Return the register's hardware encoding; e.g., `0` for `%rax`.
130 fn enc(&self) -> u8;
131
132 /// Return the register name.
133 fn to_string(&self, size: Option<gpr::Size>) -> String {
134 match size {
135 Some(size) => gpr::enc::to_string(self.enc(), size).into(),
136 None => xmm::enc::to_string(self.enc()).into(),
137 }
138 }
139}
140
141/// Provide a convenient implementation for testing.
142impl AsReg for u8 {
143 fn new(enc: u8) -> Self {
144 enc
145 }
146 fn enc(&self) -> u8 {
147 *self
148 }
149}
150
151/// Describe a visitor for the register operands of an instruction.
152///
153/// Due to how Cranelift's register allocation works, we allow the visitor to
154/// modify the register operands in place. This allows Cranelift to convert
155/// virtual registers (`[128..N)`) to physical registers (`[0..16)`) without
156/// re-allocating the entire instruction object.
157pub trait RegisterVisitor<R: Registers> {
158 /// Visit a read-only register.
159 fn read(&mut self, reg: &mut R::ReadGpr);
160 /// Visit a read-write register.
161 fn read_write(&mut self, reg: &mut R::ReadWriteGpr);
162 /// Visit a read-only fixed register; for safety, this register cannot be
163 /// modified in-place.
164 fn fixed_read(&mut self, reg: &R::ReadGpr);
165 /// Visit a read-write fixed register; for safety, this register cannot be
166 /// modified in-place.
167 fn fixed_read_write(&mut self, reg: &R::ReadWriteGpr);
168 /// Visit a read-only SSE register.
169 fn read_xmm(&mut self, reg: &mut R::ReadXmm);
170 /// Visit a read-write SSE register.
171 fn read_write_xmm(&mut self, reg: &mut R::ReadWriteXmm);
172 /// Visit a read-only fixed SSE register; for safety, this register cannot
173 /// be modified in-place.
174 fn fixed_read_xmm(&mut self, reg: &R::ReadXmm);
175 /// Visit a read-write fixed SSE register; for safety, this register cannot
176 /// be modified in-place.
177 fn fixed_read_write_xmm(&mut self, reg: &R::ReadWriteXmm);
178}