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     /// Index of the value input operand that is used to infer the controlling type variable. By
42     /// default, this is `0`, the first `value` operand. The index is relative to the values only,
43     /// ignoring immediate operands.
44     pub typevar_operand: Option<usize>,
45 }
46 
47 /// A tuple serving as a key to deduplicate InstructionFormat.
48 #[derive(Hash, PartialEq, Eq)]
49 pub(crate) struct FormatStructure {
50     pub num_value_operands: usize,
51     pub has_value_list: bool,
52     /// Tuples of (Rust field name / Rust type) for each immediate field.
53     pub imm_field_names: Vec<(&'static str, &'static str)>,
54 }
55 
56 impl fmt::Display for InstructionFormat {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>57     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
58         let imm_args = self
59             .imm_fields
60             .iter()
61             .map(|field| format!("{}: {}", field.member, field.kind.rust_type))
62             .collect::<Vec<_>>()
63             .join(", ");
64         fmt.write_fmt(format_args!(
65             "{}(imms=({}), vals={})",
66             self.name, imm_args, self.num_value_operands
67         ))?;
68         Ok(())
69     }
70 }
71 
72 impl InstructionFormat {
imm_by_name(&self, name: &'static str) -> &FormatField73     pub fn imm_by_name(&self, name: &'static str) -> &FormatField {
74         self.imm_fields
75             .iter()
76             .find(|&field| field.member == name)
77             .unwrap_or_else(|| {
78                 panic!(
79                     "unexpected immediate field named {} in instruction format {}",
80                     name, self.name
81                 )
82             })
83     }
84 
85     /// Returns a tuple that uniquely identifies the structure.
structure(&self) -> FormatStructure86     pub fn structure(&self) -> FormatStructure {
87         FormatStructure {
88             num_value_operands: self.num_value_operands,
89             has_value_list: self.has_value_list,
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 {
100     name: &'static str,
101     num_value_operands: usize,
102     has_value_list: bool,
103     imm_fields: Vec<FormatField>,
104     typevar_operand: Option<usize>,
105 }
106 
107 impl InstructionFormatBuilder {
new(name: &'static str) -> Self108     pub fn new(name: &'static str) -> Self {
109         Self {
110             name,
111             num_value_operands: 0,
112             has_value_list: false,
113             imm_fields: Vec::new(),
114             typevar_operand: None,
115         }
116     }
117 
value(mut self) -> Self118     pub fn value(mut self) -> Self {
119         self.num_value_operands += 1;
120         self
121     }
122 
varargs(mut self) -> Self123     pub fn varargs(mut self) -> Self {
124         self.has_value_list = true;
125         self
126     }
127 
imm(mut self, operand_kind: &OperandKind) -> Self128     pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
129         let field = FormatField {
130             kind: operand_kind.clone(),
131             member: operand_kind.rust_field_name,
132         };
133         self.imm_fields.push(field);
134         self
135     }
136 
imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self137     pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self {
138         let field = FormatField {
139             kind: operand_kind.clone(),
140             member,
141         };
142         self.imm_fields.push(field);
143         self
144     }
145 
typevar_operand(mut self, operand_index: usize) -> Self146     pub fn typevar_operand(mut self, operand_index: usize) -> Self {
147         assert!(self.typevar_operand.is_none());
148         assert!(self.has_value_list || operand_index < self.num_value_operands);
149         self.typevar_operand = Some(operand_index);
150         self
151     }
152 
build(self) -> Rc<InstructionFormat>153     pub fn build(self) -> Rc<InstructionFormat> {
154         let typevar_operand = if self.typevar_operand.is_some() {
155             self.typevar_operand
156         } else if self.has_value_list || self.num_value_operands > 0 {
157             // Default to the first value operand, if there's one.
158             Some(0)
159         } else {
160             None
161         };
162 
163         Rc::new(InstructionFormat {
164             name: self.name,
165             num_value_operands: self.num_value_operands,
166             has_value_list: self.has_value_list,
167             imm_fields: self.imm_fields,
168             typevar_operand,
169         })
170     }
171 }
172