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}