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> {
new(all_instructions: &'all_inst mut AllInstructions) -> Self16     pub fn new(all_instructions: &'all_inst mut AllInstructions) -> Self {
17         Self { all_instructions }
18     }
19 
push(&mut self, builder: InstructionBuilder)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 {
snake_name(&self) -> &str81     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 {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>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 {
new<S: Into<String>>(name: S, doc: S, format: &Rc<InstructionFormat>) -> Self142     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 
operands_in(mut self, operands: Vec<Operand>) -> Self162     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 
operands_out(mut self, operands: Vec<Operand>) -> Self168     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.
terminates_block(mut self) -> Self175     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.
branches(mut self) -> Self182     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.
call(mut self) -> Self188     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.
returns(mut self) -> Self195     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.
can_load(mut self) -> Self201     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.
can_store(mut self) -> Self207     pub fn can_store(mut self) -> Self {
208         self.can_store = true;
209         self
210     }
211 
212     /// Mark this instruction as possibly trapping.
can_trap(mut self) -> Self213     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.
other_side_effects(mut self) -> Self219     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.
side_effects_idempotent(mut self) -> Self225     pub fn side_effects_idempotent(mut self) -> Self {
226         self.side_effects_idempotent = true;
227         self
228     }
229 
build(self) -> Instruction230     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.
verify_format(inst_name: &str, operands_in: &[Operand], format: &InstructionFormat)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_raw_blocks = 0;
292     let mut num_immediates = 0;
293 
294     for operand in operands_in.iter() {
295         if operand.is_varargs() {
296             assert!(
297                 format.has_value_list,
298                 "instruction {} has varargs, but its format {} doesn't have a value list; you may \
299                  need to use a different format.",
300                 inst_name, format.name
301             );
302         }
303         if operand.is_value() {
304             num_values += 1;
305         }
306         if operand.kind.is_block() {
307             num_blocks += 1;
308         } else if operand.kind.is_raw_block() {
309             num_raw_blocks += 1;
310         } else if operand.is_immediate_or_entityref() {
311             if let Some(format_field) = format.imm_fields.get(num_immediates) {
312                 assert_eq!(
313                     format_field.kind.rust_field_name,
314                     operand.kind.rust_field_name,
315                     "{}th operand of {} should be {} (according to format), not {} (according to \
316                      inst definition). You may need to use a different format.",
317                     num_immediates,
318                     inst_name,
319                     format_field.kind.rust_field_name,
320                     operand.kind.rust_field_name
321                 );
322                 num_immediates += 1;
323             }
324         }
325     }
326 
327     assert_eq!(
328         num_values, format.num_value_operands,
329         "inst {} doesn't have as many value input operands as its format {} declares; you may need \
330          to use a different format.",
331         inst_name, format.name
332     );
333 
334     assert_eq!(
335         num_blocks, format.num_block_operands,
336         "inst {} doesn't have as many block input operands as its format {} declares; you may need \
337         to use a different format.",
338         inst_name, format.name,
339     );
340 
341     assert_eq!(
342         num_raw_blocks, format.num_raw_block_operands,
343         "inst {} doesn't have as many raw-block input operands as its format {} declares; you may need \
344          to use a different format.",
345         inst_name, format.name,
346     );
347 
348     assert_eq!(
349         num_immediates,
350         format.imm_fields.len(),
351         "inst {} doesn't have as many immediate input \
352          operands as its format {} declares; you may need to use a different format.",
353         inst_name,
354         format.name
355     );
356 }
357 
358 /// Check if this instruction is polymorphic, and verify its use of type variables.
verify_polymorphic( operands_in: &[Operand], operands_out: &[Operand], format: &InstructionFormat, value_opnums: &[usize], ) -> Option<PolymorphicInfo>359 fn verify_polymorphic(
360     operands_in: &[Operand],
361     operands_out: &[Operand],
362     format: &InstructionFormat,
363     value_opnums: &[usize],
364 ) -> Option<PolymorphicInfo> {
365     // The instruction is polymorphic if it has one free input or output operand.
366     let is_polymorphic = operands_in
367         .iter()
368         .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some())
369         || operands_out
370             .iter()
371             .any(|op| op.is_value() && op.type_var().unwrap().free_typevar().is_some());
372 
373     if !is_polymorphic {
374         return None;
375     }
376 
377     // Verify the use of type variables.
378     let tv_op = format.typevar_operand;
379     let mut maybe_error_message = None;
380     if let Some(tv_op) = tv_op {
381         if tv_op < value_opnums.len() {
382             let op_num = value_opnums[tv_op];
383             let tv = operands_in[op_num].type_var().unwrap();
384             let free_typevar = tv.free_typevar();
385             if (free_typevar.is_some() && tv == &free_typevar.unwrap())
386                 || tv.singleton_type().is_some()
387             {
388                 match is_ctrl_typevar_candidate(tv, operands_in, operands_out) {
389                     Ok(_other_typevars) => {
390                         return Some(PolymorphicInfo {
391                             use_typevar_operand: true,
392                             ctrl_typevar: tv.clone(),
393                         });
394                     }
395                     Err(error_message) => {
396                         maybe_error_message = Some(error_message);
397                     }
398                 }
399             }
400         }
401     };
402 
403     // If we reached here, it means the type variable indicated as the typevar operand couldn't
404     // control every other input and output type variable. We need to look at the result type
405     // variables.
406     if operands_out.is_empty() {
407         // No result means no other possible type variable, so it's a type inference failure.
408         match maybe_error_message {
409             Some(msg) => panic!("{}", msg),
410             None => panic!("typevar_operand must be a free type variable"),
411         }
412     }
413 
414     // Otherwise, try to infer the controlling type variable by looking at the first result.
415     let tv = operands_out[0].type_var().unwrap();
416     let free_typevar = tv.free_typevar();
417     if free_typevar.is_some() && tv != &free_typevar.unwrap() {
418         panic!("first result must be a free type variable");
419     }
420 
421     // At this point, if the next unwrap() fails, it means the output type couldn't be used as a
422     // controlling type variable either; panicking is the right behavior.
423     is_ctrl_typevar_candidate(tv, operands_in, operands_out).unwrap();
424 
425     Some(PolymorphicInfo {
426         use_typevar_operand: false,
427         ctrl_typevar: tv.clone(),
428     })
429 }
430 
431 /// Verify that the use of TypeVars is consistent with `ctrl_typevar` as the controlling type
432 /// variable.
433 ///
434 /// All polymorphic inputs must either be derived from `ctrl_typevar` or be independent free type
435 /// variables only used once.
436 ///
437 /// All polymorphic results must be derived from `ctrl_typevar`.
438 ///
439 /// Return a vector of other type variables used, or a string explaining what went wrong.
is_ctrl_typevar_candidate( ctrl_typevar: &TypeVar, operands_in: &[Operand], operands_out: &[Operand], ) -> Result<Vec<TypeVar>, String>440 fn is_ctrl_typevar_candidate(
441     ctrl_typevar: &TypeVar,
442     operands_in: &[Operand],
443     operands_out: &[Operand],
444 ) -> Result<Vec<TypeVar>, String> {
445     let mut other_typevars = Vec::new();
446 
447     // Check value inputs.
448     for input in operands_in {
449         if !input.is_value() {
450             continue;
451         }
452 
453         let typ = input.type_var().unwrap();
454         let free_typevar = typ.free_typevar();
455 
456         // Non-polymorphic or derived from ctrl_typevar is OK.
457         if free_typevar.is_none() {
458             continue;
459         }
460         let free_typevar = free_typevar.unwrap();
461         if &free_typevar == ctrl_typevar {
462             continue;
463         }
464 
465         // No other derived typevars allowed.
466         if typ != &free_typevar {
467             return Err(format!(
468                 "{:?}: type variable {} must be derived from {:?} while it is derived from {:?}",
469                 input, typ.name, ctrl_typevar, free_typevar
470             ));
471         }
472 
473         // Other free type variables can only be used once each.
474         for other_tv in &other_typevars {
475             if &free_typevar == other_tv {
476                 return Err(format!(
477                     "non-controlling type variable {} can't be used more than once",
478                     free_typevar.name
479                 ));
480             }
481         }
482 
483         other_typevars.push(free_typevar);
484     }
485 
486     // Check outputs.
487     for result in operands_out {
488         if !result.is_value() {
489             continue;
490         }
491 
492         let typ = result.type_var().unwrap();
493         let free_typevar = typ.free_typevar();
494 
495         // Non-polymorphic or derived from ctrl_typevar is OK.
496         if free_typevar.is_none() || &free_typevar.unwrap() == ctrl_typevar {
497             continue;
498         }
499 
500         return Err("type variable in output not derived from ctrl_typevar".into());
501     }
502 
503     Ok(other_typevars)
504 }
505