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     /// Index of the value input operand that is used to infer the controlling type variable. By
44     /// default, this is `0`, the first `value` operand. The index is relative to the values only,
45     /// ignoring immediate operands.
46     pub typevar_operand: Option<usize>,
47 }
48 
49 /// A tuple serving as a key to deduplicate InstructionFormat.
50 #[derive(Hash, PartialEq, Eq)]
51 pub(crate) struct FormatStructure {
52     pub num_value_operands: usize,
53     pub has_value_list: bool,
54     pub num_block_operands: usize,
55     /// Tuples of (Rust field name / Rust type) for each immediate field.
56     pub imm_field_names: Vec<(&'static str, &'static str)>,
57 }
58 
59 impl fmt::Display for InstructionFormat {
60     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
61         let imm_args = self
62             .imm_fields
63             .iter()
64             .map(|field| format!("{}: {}", field.member, field.kind.rust_type))
65             .collect::<Vec<_>>()
66             .join(", ");
67         fmt.write_fmt(format_args!(
68             "{}(imms=({}), vals={}, blocks={})",
69             self.name, imm_args, self.num_value_operands, self.num_block_operands,
70         ))?;
71         Ok(())
72     }
73 }
74 
75 impl InstructionFormat {
76     /// Returns a tuple that uniquely identifies the structure.
77     pub fn structure(&self) -> FormatStructure {
78         FormatStructure {
79             num_value_operands: self.num_value_operands,
80             has_value_list: self.has_value_list,
81             num_block_operands: self.num_block_operands,
82             imm_field_names: self
83                 .imm_fields
84                 .iter()
85                 .map(|field| (field.kind.rust_field_name, field.kind.rust_type))
86                 .collect::<Vec<_>>(),
87         }
88     }
89 }
90 
91 pub(crate) struct InstructionFormatBuilder(InstructionFormat);
92 
93 impl InstructionFormatBuilder {
94     pub fn new(name: &'static str) -> Self {
95         Self(InstructionFormat {
96             name,
97             num_value_operands: 0,
98             has_value_list: false,
99             num_block_operands: 0,
100             imm_fields: Vec::new(),
101             typevar_operand: None,
102         })
103     }
104 
105     pub fn value(mut self) -> Self {
106         self.0.num_value_operands += 1;
107         self
108     }
109 
110     pub fn varargs(mut self) -> Self {
111         self.0.has_value_list = true;
112         self
113     }
114 
115     pub fn block(mut self) -> Self {
116         self.0.num_block_operands += 1;
117         self
118     }
119 
120     pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
121         let field = FormatField {
122             kind: operand_kind.clone(),
123             member: operand_kind.rust_field_name,
124         };
125         self.0.imm_fields.push(field);
126         self
127     }
128 
129     pub fn typevar_operand(mut self, operand_index: usize) -> Self {
130         assert!(self.0.typevar_operand.is_none());
131         assert!(operand_index < self.0.num_value_operands);
132         self.0.typevar_operand = Some(operand_index);
133         self
134     }
135 
136     pub fn build(mut self) -> Rc<InstructionFormat> {
137         if self.0.typevar_operand.is_none() && self.0.num_value_operands > 0 {
138             // Default to the first value operand, if there's one.
139             self.0.typevar_operand = Some(0);
140         };
141 
142         Rc::new(self.0)
143     }
144 }
145