1 //! Contains traits that a user of this assembler must implement.
2 
3 use crate::gpr;
4 use crate::xmm;
5 use std::{num::NonZeroU8, ops::Index, vec::Vec};
6 
7 /// Describe how an instruction is emitted into a code buffer.
8 pub 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.
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 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))]
72 pub 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))]
77 pub 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))]
82 pub 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`.
93 pub trait KnownOffsetTable: Index<KnownOffset, Output = i32> {}
94 impl KnownOffsetTable for Vec<i32> {}
95 /// Provide a convenient implementation for testing.
96 impl KnownOffsetTable for [i32; 2] {}
97 
98 /// A `KnownOffset` is a unique identifier for a specific offset known only at
99 /// emission time.
100 pub 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.
107 pub 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.
122 pub 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.
142 impl 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.
157 pub 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 }
179