1 use std::fmt;
2 use std::rc::Rc;
3 
4 use crate::cdsl::camel_case;
5 use crate::cdsl::formats::InstructionFormat;
6 use crate::cdsl::operands::Operand;
7 use crate::cdsl::typevar::TypeVar;
8 
9 pub(crate) type AllInstructions = Vec<Instruction>;
10 
11 pub(crate) struct InstructionGroupBuilder<'all_inst> {
12     all_instructions: &'all_inst mut AllInstructions,
13 }
14 
15 impl<'all_inst> InstructionGroupBuilder<'all_inst> {
16     pub fn new(all_instructions: &'all_inst mut AllInstructions) -> Self {
17         Self { all_instructions }
18     }
19 
20     pub fn push(&mut self, builder: InstructionBuilder) {
21         let inst = builder.build();
22         self.all_instructions.push(inst);
23     }
24 }
25 
26 #[derive(Debug)]
27 pub(crate) struct PolymorphicInfo {
28     pub use_typevar_operand: bool,
29     pub ctrl_typevar: TypeVar,
30 }
31 
32 #[derive(Debug)]
33 pub(crate) struct InstructionContent {
34     /// Instruction mnemonic, also becomes opcode name.
35     pub name: String,
36     pub camel_name: String,
37 
38     /// Documentation string.
39     pub doc: String,
40 
41     /// Input operands. This can be a mix of SSA value operands and other operand kinds.
42     pub operands_in: Vec<Operand>,
43     /// Output operands. The output operands must be SSA values or `variable_args`.
44     pub operands_out: Vec<Operand>,
45 
46     /// Instruction format.
47     pub format: Rc<InstructionFormat>,
48 
49     /// One of the input or output operands is a free type variable. None if the instruction is not
50     /// polymorphic, set otherwise.
51     pub polymorphic_info: Option<PolymorphicInfo>,
52 
53     /// Indices in operands_in of input operands that are values.
54     pub value_opnums: Vec<usize>,
55     /// Indices in operands_in of input operands that are immediates or entities.
56     pub imm_opnums: Vec<usize>,
57     /// Indices in operands_out of output operands that are values.
58     pub value_results: Vec<usize>,
59 
60     /// True for instructions that terminate the block.
61     pub is_terminator: bool,
62     /// True for all branch or jump instructions.
63     pub is_branch: bool,
64     /// Is this a call instruction?
65     pub is_call: bool,
66     /// Is this a return instruction?
67     pub is_return: bool,
68     /// Can this instruction read from memory?
69     pub can_load: bool,
70     /// Can this instruction write to memory?
71     pub can_store: bool,
72     /// Can this instruction cause a trap?
73     pub can_trap: bool,
74     /// Does this instruction have other side effects besides can_* flags?
75     pub other_side_effects: bool,
76     /// Despite having other side effects, is this instruction okay to GVN?
77     pub side_effects_idempotent: bool,
78 }
79 
80 impl InstructionContent {
81     pub fn snake_name(&self) -> &str {
82         if &self.name == "return" {
83             "return_"
84         } else {
85             &self.name
86         }
87     }
88 }
89 
90 pub(crate) type Instruction = Rc<InstructionContent>;
91 
92 impl fmt::Display for InstructionContent {
93     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
94         if !self.operands_out.is_empty() {
95             let operands_out = self
96                 .operands_out
97                 .iter()
98                 .map(|op| op.name)
99                 .collect::<Vec<_>>()
100                 .join(", ");
101             fmt.write_str(&operands_out)?;
102             fmt.write_str(" = ")?;
103         }
104 
105         fmt.write_str(&self.name)?;
106 
107         if !self.operands_in.is_empty() {
108             let operands_in = self
109                 .operands_in
110                 .iter()
111                 .map(|op| op.name)
112                 .collect::<Vec<_>>()
113                 .join(", ");
114             fmt.write_str(" ")?;
115             fmt.write_str(&operands_in)?;
116         }
117 
118         Ok(())
119     }
120 }
121 
122 pub(crate) struct InstructionBuilder {
123     name: String,
124     doc: String,
125     format: Rc<InstructionFormat>,
126     operands_in: Option<Vec<Operand>>,
127     operands_out: Option<Vec<Operand>>,
128 
129     // See Instruction comments for the meaning of these fields.
130     is_terminator: bool,
131     is_branch: bool,
132     is_call: bool,
133     is_return: bool,
134     can_load: bool,
135     can_store: bool,
136     can_trap: bool,
137     other_side_effects: bool,
138     side_effects_idempotent: bool,
139 }
140 
141 impl InstructionBuilder {
142     pub fn new<S: Into<String>>(name: S, doc: S, format: &Rc<InstructionFormat>) -> Self {
143         Self {
144             name: name.into(),
145             doc: doc.into(),
146             format: format.clone(),
147             operands_in: None,
148             operands_out: None,
149 
150             is_terminator: false,
151             is_branch: false,
152             is_call: false,
153             is_return: false,
154             can_load: false,
155             can_store: false,
156             can_trap: false,
157             other_side_effects: false,
158             side_effects_idempotent: false,
159         }
160     }
161 
162     pub fn operands_in(mut self, operands: Vec<Operand>) -> Self {
163         assert!(self.operands_in.is_none());
164         self.operands_in = Some(operands);
165         self
166     }
167 
168     pub fn operands_out(mut self, operands: Vec<Operand>) -> Self {
169         assert!(self.operands_out.is_none());
170         self.operands_out = Some(operands);
171         self
172     }
173 
174     /// Mark this instruction as a block terminator.
175     pub fn terminates_block(mut self) -> Self {
176         self.is_terminator = true;
177         self
178     }
179 
180     /// Mark this instruction as a branch instruction. This also implies that the instruction is a
181     /// block terminator.
182     pub fn branches(mut self) -> Self {
183         self.is_branch = true;
184         self.terminates_block()
185     }
186 
187     /// Mark this instruction as a call instruction.
188     pub fn call(mut self) -> Self {
189         self.is_call = true;
190         self
191     }
192 
193     /// Mark this instruction as a return instruction. This also implies that the instruction is a
194     /// block terminator.
195     pub fn returns(mut self) -> Self {
196         self.is_return = true;
197         self.terminates_block()
198     }
199 
200     /// Mark this instruction as one that can load from memory.
201     pub fn can_load(mut self) -> Self {
202         self.can_load = true;
203         self
204     }
205 
206     /// Mark this instruction as one that can store to memory.
207     pub fn can_store(mut self) -> Self {
208         self.can_store = true;
209         self
210     }
211 
212     /// Mark this instruction as possibly trapping.
213     pub fn can_trap(mut self) -> Self {
214         self.can_trap = true;
215         self
216     }
217 
218     /// Mark this instruction as one that has side-effects.
219     pub fn other_side_effects(mut self) -> Self {
220         self.other_side_effects = true;
221         self
222     }
223 
224     /// Mark this instruction as one whose side-effects may be de-duplicated.
225     pub fn side_effects_idempotent(mut self) -> Self {
226         self.side_effects_idempotent = true;
227         self
228     }
229 
230     fn build(self) -> Instruction {
231         let operands_in = self.operands_in.unwrap_or_default();
232         let operands_out = self.operands_out.unwrap_or_default();
233 
234         let mut value_opnums = Vec::new();
235         let mut imm_opnums = Vec::new();
236         for (i, op) in operands_in.iter().enumerate() {
237             if op.is_value() {
238                 value_opnums.push(i);
239             } else if op.is_immediate_or_entityref() {
240                 imm_opnums.push(i);
241             } else {
242                 assert!(op.is_varargs());
243             }
244         }
245 
246         let value_results = operands_out
247             .iter()
248             .enumerate()
249             .filter_map(|(i, op)| if op.is_value() { Some(i) } else { None })
250             .collect();
251 
252         verify_format(&self.name, &operands_in, &self.format);
253 
254         let polymorphic_info =
255             verify_polymorphic(&operands_in, &operands_out, &self.format, &value_opnums);
256 
257         let camel_name = camel_case(&self.name);
258 
259         Rc::new(InstructionContent {
260             name: self.name,
261             camel_name,
262             doc: self.doc,
263             operands_in,
264             operands_out,
265             format: self.format,
266             polymorphic_info,
267             value_opnums,
268             value_results,
269             imm_opnums,
270             is_terminator: self.is_terminator,
271             is_branch: self.is_branch,
272             is_call: self.is_call,
273             is_return: self.is_return,
274             can_load: self.can_load,
275             can_store: self.can_store,
276             can_trap: self.can_trap,
277             other_side_effects: self.other_side_effects,
278             side_effects_idempotent: self.side_effects_idempotent,
279         })
280     }
281 }
282 
283 /// Checks that the input operands actually match the given format.
284 fn verify_format(inst_name: &str, operands_in: &[Operand], format: &InstructionFormat) {
285     // A format is defined by:
286     // - its number of input value operands,
287     // - its number and names of input immediate operands,
288     // - whether it has a value list or not.
289     let mut num_values = 0;
290     let mut num_blocks = 0;
291     let mut num_immediates = 0;
292 
293     for operand in operands_in.iter() {
294         if operand.is_varargs() {
295             assert!(
296                 format.has_value_list,
297                 "instruction {} has varargs, but its format {} doesn't have a value list; you may \
298                  need to use a different format.",
299                 inst_name, format.name
300             );
301         }
302         if operand.is_value() {
303             num_values += 1;
304         }
305         if operand.kind.is_block() {
306             num_blocks += 1;
307         } else if operand.is_immediate_or_entityref() {
308             if let Some(format_field) = format.imm_fields.get(num_immediates) {
309                 assert_eq!(
310                     format_field.kind.rust_field_name,
311                     operand.kind.rust_field_name,
312                     "{}th operand of {} should be {} (according to format), not {} (according to \
313                      inst definition). You may need to use a different format.",
314                     num_immediates,
315                     inst_name,
316                     format_field.kind.rust_field_name,
317                     operand.kind.rust_field_name
318                 );
319                 num_immediates += 1;
320             }
321         }
322     }
323 
324     assert_eq!(
325         num_values, format.num_value_operands,
326         "inst {} doesn't have as many value input operands as its format {} declares; you may need \
327          to use a different format.",
328         inst_name, format.name
329     );
330 
331     assert_eq!(
332         num_blocks, format.num_block_operands,
333         "inst {} doesn't have as many block input operands as its format {} declares; you may need \
334         to use a different format.",
335         inst_name, format.name,
336     );
337 
338     assert_eq!(
339         num_immediates,
340         format.imm_fields.len(),
341         "inst {} doesn't have as many immediate input \
342          operands as its format {} declares; you may need to use a different format.",
343         inst_name,
344         format.name
345     );
346 }
347 
348 /// Check if this instruction is polymorphic, and verify its use of type variables.
349 fn verify_polymorphic(
350     operands_in: &[Operand],
351     operands_out: &[Operand],
352     format: &InstructionFormat,
353     value_opnums: &[usize],
354 ) -> Option<PolymorphicInfo> {
355     // The instruction is polymorphic if it has one free input or output operand.
356     let is_polymorphic = operands_in
357         .iter()
358         .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some())
359         || operands_out
360             .iter()
361             .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some());
362 
363     if !is_polymorphic {
364         return None;
365     }
366 
367     // Verify the use of type variables.
368     let tv_op = format.typevar_operand;
369     let mut maybe_error_message = None;
370     if let Some(tv_op) = tv_op {
371         if tv_op < value_opnums.len() {
372             let op_num = value_opnums[tv_op];
373             let tv = operands_in[op_num].type_var().unwrap();
374             let free_typevar = tv.free_typevar();
375             if (free_typevar.is_some() && tv == &free_typevar.unwrap())
376                 || tv.singleton_type().is_some()
377             {
378                 match is_ctrl_typevar_candidate(tv, operands_in, operands_out) {
379                     Ok(_other_typevars) => {
380                         return Some(PolymorphicInfo {
381                             use_typevar_operand: true,
382                             ctrl_typevar: tv.clone(),
383                         });
384                     }
385                     Err(error_message) => {
386                         maybe_error_message = Some(error_message);
387                     }
388                 }
389             }
390         }
391     };
392 
393     // If we reached here, it means the type variable indicated as the typevar operand couldn't
394     // control every other input and output type variable. We need to look at the result type
395     // variables.
396     if operands_out.is_empty() {
397         // No result means no other possible type variable, so it's a type inference failure.
398         match maybe_error_message {
399             Some(msg) => panic!("{}", msg),
400             None => panic!("typevar_operand must be a free type variable"),
401         }
402     }
403 
404     // Otherwise, try to infer the controlling type variable by looking at the first result.
405     let tv = operands_out[0].type_var().unwrap();
406     let free_typevar = tv.free_typevar();
407     if free_typevar.is_some() && tv != &free_typevar.unwrap() {
408         panic!("first result must be a free type variable");
409     }
410 
411     // At this point, if the next unwrap() fails, it means the output type couldn't be used as a
412     // controlling type variable either; panicking is the right behavior.
413     is_ctrl_typevar_candidate(tv, operands_in, operands_out).unwrap();
414 
415     Some(PolymorphicInfo {
416         use_typevar_operand: false,
417         ctrl_typevar: tv.clone(),
418     })
419 }
420 
421 /// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type
422 /// variable.
423 ///
424 /// All polymorphic inputs must either be derived from `ctrl_typevar` or be independent free type
425 /// variables only used once.
426 ///
427 /// All polymorphic results must be derived from `ctrl_typevar`.
428 ///
429 /// Return a vector of other type variables used, or a string explaining what went wrong.
430 fn is_ctrl_typevar_candidate(
431     ctrl_typevar: &TypeVar,
432     operands_in: &[Operand],
433     operands_out: &[Operand],
434 ) -> Result<Vec<TypeVar>, String> {
435     let mut other_typevars = Vec::new();
436 
437     // Check value inputs.
438     for input in operands_in {
439         if !input.is_value() {
440             continue;
441         }
442 
443         let typ = input.type_var().unwrap();
444         let free_typevar = typ.free_typevar();
445 
446         // Non-polymorphic or derived from ctrl_typevar is OK.
447         if free_typevar.is_none() {
448             continue;
449         }
450         let free_typevar = free_typevar.unwrap();
451         if &free_typevar == ctrl_typevar {
452             continue;
453         }
454 
455         // No other derived typevars allowed.
456         if typ != &free_typevar {
457             return Err(format!(
458                 "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}",
459                 input, typ.name, ctrl_typevar, free_typevar
460             ));
461         }
462 
463         // Other free type variables can only be used once each.
464         for other_tv in &other_typevars {
465             if &free_typevar == other_tv {
466                 return Err(format!(
467                     "non-controlling type variable {} can't be used more than once",
468                     free_typevar.name
469                 ));
470             }
471         }
472 
473         other_typevars.push(free_typevar);
474     }
475 
476     // Check outputs.
477     for result in operands_out {
478         if !result.is_value() {
479             continue;
480         }
481 
482         let typ = result.type_var().unwrap();
483         let free_typevar = typ.free_typevar();
484 
485         // Non-polymorphic or derived from ctrl_typevar is OK.
486         if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar {
487             continue;
488         }
489 
490         return Err("type variable in output not derived from ctrl_typevar".into());
491     }
492 
493     Ok(other_typevars)
494 }
495