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}