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