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