1 //! The `Encoding` struct.
2
3 use crate::binemit::CodeOffset;
4 use crate::ir::{Function, Inst};
5 use crate::isa::constraints::{BranchRange, RecipeConstraints};
6 use crate::regalloc::RegDiversions;
7 use core::fmt;
8
9 /// Bits needed to encode an instruction as binary machine code.
10 ///
11 /// The encoding consists of two parts, both specific to the target ISA: An encoding *recipe*, and
12 /// encoding *bits*. The recipe determines the native instruction format and the mapping of
13 /// operands to encoded bits. The encoding bits provide additional information to the recipe,
14 /// typically parts of the opcode.
15 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
16 pub struct Encoding {
17 recipe: u16,
18 bits: u16,
19 }
20
21 impl Encoding {
22 /// Create a new `Encoding` containing `(recipe, bits)`.
new(recipe: u16, bits: u16) -> Self23 pub fn new(recipe: u16, bits: u16) -> Self {
24 Self { recipe, bits }
25 }
26
27 /// Get the recipe number in this encoding.
recipe(self) -> usize28 pub fn recipe(self) -> usize {
29 self.recipe as usize
30 }
31
32 /// Get the recipe-specific encoding bits.
bits(self) -> u1633 pub fn bits(self) -> u16 {
34 self.bits
35 }
36
37 /// Is this a legal encoding, or the default placeholder?
is_legal(self) -> bool38 pub fn is_legal(self) -> bool {
39 self != Self::default()
40 }
41 }
42
43 /// The default encoding is the illegal one.
44 impl Default for Encoding {
default() -> Self45 fn default() -> Self {
46 Self::new(0xffff, 0xffff)
47 }
48 }
49
50 /// ISA-independent display of an encoding.
51 impl fmt::Display for Encoding {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 if self.is_legal() {
54 write!(f, "{}#{:02x}", self.recipe, self.bits)
55 } else {
56 write!(f, "-")
57 }
58 }
59 }
60
61 /// Temporary object that holds enough context to properly display an encoding.
62 /// This is meant to be created by `EncInfo::display()`.
63 pub struct DisplayEncoding {
64 pub encoding: Encoding,
65 pub recipe_names: &'static [&'static str],
66 }
67
68 impl fmt::Display for DisplayEncoding {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 if self.encoding.is_legal() {
71 write!(
72 f,
73 "{}#{:02x}",
74 self.recipe_names[self.encoding.recipe()],
75 self.encoding.bits
76 )
77 } else {
78 write!(f, "-")
79 }
80 }
81 }
82
83 type SizeCalculatorFn = fn(&RecipeSizing, Encoding, Inst, &RegDiversions, &Function) -> u8;
84
85 /// Returns the base size of the Recipe, assuming it's fixed. This is the default for most
86 /// encodings; others can be variable and longer than this base size, depending on the registers
87 /// they're using and use a different function, specific per platform.
base_size( sizing: &RecipeSizing, _: Encoding, _: Inst, _: &RegDiversions, _: &Function, ) -> u888 pub fn base_size(
89 sizing: &RecipeSizing,
90 _: Encoding,
91 _: Inst,
92 _: &RegDiversions,
93 _: &Function,
94 ) -> u8 {
95 sizing.base_size
96 }
97
98 /// Code size information for an encoding recipe.
99 ///
100 /// Encoding recipes may have runtime-determined instruction size.
101 pub struct RecipeSizing {
102 /// Minimum size in bytes of instructions encoded with this recipe.
103 pub base_size: u8,
104
105 /// Method computing the instruction's real size, given inputs and outputs.
106 pub compute_size: SizeCalculatorFn,
107
108 /// Allowed branch range in this recipe, if any.
109 ///
110 /// All encoding recipes for branches have exact branch range information.
111 pub branch_range: Option<BranchRange>,
112 }
113
114 /// Information about all the encodings in this ISA.
115 #[derive(Clone)]
116 pub struct EncInfo {
117 /// Constraints on value operands per recipe.
118 pub constraints: &'static [RecipeConstraints],
119
120 /// Code size information per recipe.
121 pub sizing: &'static [RecipeSizing],
122
123 /// Names of encoding recipes.
124 pub names: &'static [&'static str],
125 }
126
127 impl EncInfo {
128 /// Get the value operand constraints for `enc` if it is a legal encoding.
operand_constraints(&self, enc: Encoding) -> Option<&'static RecipeConstraints>129 pub fn operand_constraints(&self, enc: Encoding) -> Option<&'static RecipeConstraints> {
130 self.constraints.get(enc.recipe())
131 }
132
133 /// Create an object that can display an ISA-dependent encoding properly.
display(&self, enc: Encoding) -> DisplayEncoding134 pub fn display(&self, enc: Encoding) -> DisplayEncoding {
135 DisplayEncoding {
136 encoding: enc,
137 recipe_names: self.names,
138 }
139 }
140
141 /// Get the size in bytes of `inst`, if it were encoded with `enc`.
142 ///
143 /// Returns 0 for illegal encodings.
byte_size( &self, enc: Encoding, inst: Inst, divert: &RegDiversions, func: &Function, ) -> CodeOffset144 pub fn byte_size(
145 &self,
146 enc: Encoding,
147 inst: Inst,
148 divert: &RegDiversions,
149 func: &Function,
150 ) -> CodeOffset {
151 self.sizing.get(enc.recipe()).map_or(0, |s| {
152 let compute_size = s.compute_size;
153 CodeOffset::from(compute_size(&s, enc, inst, divert, func))
154 })
155 }
156
157 /// Get the branch range that is supported by `enc`, if any.
158 ///
159 /// This will never return `None` for a legal branch encoding.
branch_range(&self, enc: Encoding) -> Option<BranchRange>160 pub fn branch_range(&self, enc: Encoding) -> Option<BranchRange> {
161 self.sizing.get(enc.recipe()).and_then(|s| s.branch_range)
162 }
163 }
164