1 use crate::cdsl::operands::OperandKind;
2 use std::fmt;
3 use std::rc::Rc;
4 
5 /// An immediate field in an instruction format.
6 ///
7 /// This corresponds to a single member of a variant of the `InstructionData`
8 /// data type.
9 #[derive(Debug)]
10 pub(crate) struct FormatField {
11     /// Immediate operand kind.
12     pub kind: OperandKind,
13 
14     /// Member name in InstructionData variant.
15     pub member: &'static str,
16 }
17 
18 /// Every instruction opcode has a corresponding instruction format which determines the number of
19 /// operands and their kinds. Instruction formats are identified structurally, i.e., the format of
20 /// an instruction is derived from the kinds of operands used in its declaration.
21 ///
22 /// The instruction format stores two separate lists of operands: Immediates and values. Immediate
23 /// operands (including entity references) are represented as explicit members in the
24 /// `InstructionData` variants. The value operands are stored differently, depending on how many
25 /// there are.  Beyond a certain point, instruction formats switch to an external value list for
26 /// storing value arguments. Value lists can hold an arbitrary number of values.
27 ///
28 /// All instruction formats must be predefined in the meta shared/formats.rs module.
29 #[derive(Debug)]
30 pub(crate) struct InstructionFormat {
31     /// Instruction format name in CamelCase. This is used as a Rust variant name in both the
32     /// `InstructionData` and `InstructionFormat` enums.
33     pub name: &'static str,
34 
35     pub num_value_operands: usize,
36 
37     pub has_value_list: bool,
38 
39     pub imm_fields: Vec<FormatField>,
40 
41     pub num_block_operands: usize,
42 
43     pub num_raw_block_operands: usize,
44 
45     /// Index of the value input operand that is used to infer the controlling type variable. By
46     /// default, this is `0`, the first `value` operand. The index is relative to the values only,
47     /// ignoring immediate operands.
48     pub typevar_operand: Option<usize>,
49 }
50 
51 /// A tuple serving as a key to deduplicate InstructionFormat.
52 #[derive(Hash, PartialEq, Eq)]
53 pub(crate) struct FormatStructure {
54     pub num_value_operands: usize,
55     pub has_value_list: bool,
56     pub num_block_operands: usize,
57     pub num_raw_block_operands: usize,
58     /// Tuples of (Rust field name / Rust type) for each immediate field.
59     pub imm_field_names: Vec<(&'static str, &'static str)>,
60 }
61 
62 impl fmt::Display for InstructionFormat {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>63     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
64         let imm_args = self
65             .imm_fields
66             .iter()
67             .map(|field| format!("{}: {}", field.member, field.kind.rust_type))
68             .collect::<Vec<_>>()
69             .join(", ");
70         fmt.write_fmt(format_args!(
71             "{}(imms=({}), vals={}, blocks={}, raw_blocks={})",
72             self.name,
73             imm_args,
74             self.num_value_operands,
75             self.num_block_operands,
76             self.num_raw_block_operands,
77         ))?;
78         Ok(())
79     }
80 }
81 
82 impl InstructionFormat {
83     /// Returns a tuple that uniquely identifies the structure.
structure(&self) -> FormatStructure84     pub fn structure(&self) -> FormatStructure {
85         FormatStructure {
86             num_value_operands: self.num_value_operands,
87             has_value_list: self.has_value_list,
88             num_block_operands: self.num_block_operands,
89             num_raw_block_operands: self.num_raw_block_operands,
90             imm_field_names: self
91                 .imm_fields
92                 .iter()
93                 .map(|field| (field.kind.rust_field_name, field.kind.rust_type))
94                 .collect::<Vec<_>>(),
95         }
96     }
97 }
98 
99 pub(crate) struct InstructionFormatBuilder(InstructionFormat);
100 
101 impl InstructionFormatBuilder {
new(name: &'static str) -> Self102     pub fn new(name: &'static str) -> Self {
103         Self(InstructionFormat {
104             name,
105             num_value_operands: 0,
106             has_value_list: false,
107             num_block_operands: 0,
108             num_raw_block_operands: 0,
109             imm_fields: Vec::new(),
110             typevar_operand: None,
111         })
112     }
113 
value(mut self) -> Self114     pub fn value(mut self) -> Self {
115         self.0.num_value_operands += 1;
116         self
117     }
118 
varargs(mut self) -> Self119     pub fn varargs(mut self) -> Self {
120         self.0.has_value_list = true;
121         self
122     }
123 
block(mut self) -> Self124     pub fn block(mut self) -> Self {
125         self.0.num_block_operands += 1;
126         self
127     }
128 
raw_block(mut self) -> Self129     pub fn raw_block(mut self) -> Self {
130         self.0.num_raw_block_operands += 1;
131         self
132     }
133 
imm(mut self, operand_kind: &OperandKind) -> Self134     pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
135         let field = FormatField {
136             kind: operand_kind.clone(),
137             member: operand_kind.rust_field_name,
138         };
139         self.0.imm_fields.push(field);
140         self
141     }
142 
typevar_operand(mut self, operand_index: usize) -> Self143     pub fn typevar_operand(mut self, operand_index: usize) -> Self {
144         assert!(self.0.typevar_operand.is_none());
145         assert!(operand_index < self.0.num_value_operands);
146         self.0.typevar_operand = Some(operand_index);
147         self
148     }
149 
build(mut self) -> Rc<InstructionFormat>150     pub fn build(mut self) -> Rc<InstructionFormat> {
151         if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 {
152             // Default to the first value operand, if there's one.
153             self.0.typevar_operand = Some(0);
154         };
155 
156         Rc::new(self.0)
157     }
158 }
159