1use std::fmt;
3
4use cranelift_codegen_shared::constant_hash;
5use cranelift_entity::EntityRef;
6
7use crate::cdsl::camel_case;
8use crate::cdsl::formats::InstructionFormat;
9use crate::cdsl::instructions::{AllInstructions, Instruction};
10use crate::cdsl::operands::Operand;
11use crate::cdsl::typevar::{TypeSet, TypeVar};
12
13use crate::error;
14use crate::srcgen::{Formatter, Match};
15use crate::unique_table::{UniqueSeqTable, UniqueTable};
16
17const TYPESET_LIMIT: usize = 0xff;
19
20fn gen_formats(formats: &[&InstructionFormat], fmt: &mut Formatter) {
22 fmt.doc_comment(
23 r#"
24 An instruction format
25
26 Every opcode has a corresponding instruction format
27 which is represented by both the `InstructionFormat`
28 and the `InstructionData` enums.
29 "#,
30 );
31 fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug)]");
32 fmt.line("pub enum InstructionFormat {");
33 fmt.indent(|fmt| {
34 for format in formats {
35 fmt.doc_comment(format.to_string());
36 fmtln!(fmt, "{},", format.name);
37 }
38 });
39 fmt.line("}");
40 fmt.empty_line();
41
42 fmt.line("impl<'a> From<&'a InstructionData> for InstructionFormat {");
45 fmt.indent(|fmt| {
46 fmt.line("fn from(inst: &'a InstructionData) -> Self {");
47 fmt.indent(|fmt| {
48 let mut m = Match::new("*inst");
49 for format in formats {
50 m.arm(
51 format!("InstructionData::{}", format.name),
52 vec![".."],
53 format!("Self::{}", format.name),
54 );
55 }
56 fmt.add_match(m);
57 });
58 fmt.line("}");
59 });
60 fmt.line("}");
61 fmt.empty_line();
62}
63
64fn gen_instruction_data(formats: &[&InstructionFormat], fmt: &mut Formatter) {
70 fmt.line("#[derive(Clone, Debug)]");
71 fmt.line("#[allow(missing_docs)]");
72 fmt.line("pub enum InstructionData {");
73 fmt.indent(|fmt| {
74 for format in formats {
75 fmtln!(fmt, "{} {{", format.name);
76 fmt.indent(|fmt| {
77 fmt.line("opcode: Opcode,");
78 if format.typevar_operand.is_some() {
79 if format.has_value_list {
80 fmt.line("args: ValueList,");
81 } else if format.num_value_operands == 1 {
82 fmt.line("arg: Value,");
83 } else {
84 fmtln!(fmt, "args: [Value; {}],", format.num_value_operands);
85 }
86 }
87 for field in &format.imm_fields {
88 fmtln!(fmt, "{}: {},", field.member, field.kind.rust_type);
89 }
90 });
91 fmtln!(fmt, "},");
92 }
93 });
94 fmt.line("}");
95}
96
97fn gen_arguments_method(formats: &[&InstructionFormat], fmt: &mut Formatter, is_mut: bool) {
98 let (method, mut_, rslice, as_slice) = if is_mut {
99 (
100 "arguments_mut",
101 "mut ",
102 "core::slice::from_mut",
103 "as_mut_slice",
104 )
105 } else {
106 ("arguments", "", "core::slice::from_ref", "as_slice")
107 };
108
109 fmtln!(
110 fmt,
111 "pub fn {}<'a>(&'a {}self, pool: &'a {}ir::ValueListPool) -> &{}[Value] {{",
112 method,
113 mut_,
114 mut_,
115 mut_
116 );
117 fmt.indent(|fmt| {
118 let mut m = Match::new("*self");
119 for format in formats {
120 let name = format!("Self::{}", format.name);
121
122 if format.has_value_list {
126 m.arm(
127 name,
128 vec![format!("ref {}args", mut_), "..".to_string()],
129 format!("args.{}(pool)", as_slice),
130 );
131 continue;
132 }
133
134 let mut fields = Vec::new();
136 let arg = if format.num_value_operands == 0 {
137 format!("&{}[]", mut_)
138 } else if format.num_value_operands == 1 {
139 fields.push(format!("ref {}arg", mut_));
140 format!("{}(arg)", rslice)
141 } else {
142 let arg = format!("args_arity{}", format.num_value_operands);
143 fields.push(format!("args: ref {}{}", mut_, arg));
144 arg
145 };
146 fields.push("..".into());
147
148 m.arm(name, fields, arg);
149 }
150 fmt.add_match(m);
151 });
152 fmtln!(fmt, "}");
153}
154
155fn gen_instruction_data_impl(formats: &[&InstructionFormat], fmt: &mut Formatter) {
168 fmt.line("impl InstructionData {");
169 fmt.indent(|fmt| {
170 fmt.doc_comment("Get the opcode of this instruction.");
171 fmt.line("pub fn opcode(&self) -> Opcode {");
172 fmt.indent(|fmt| {
173 let mut m = Match::new("*self");
174 for format in formats {
175 m.arm(format!("Self::{}", format.name), vec!["opcode", ".."],
176 "opcode".to_string());
177 }
178 fmt.add_match(m);
179 });
180 fmt.line("}");
181 fmt.empty_line();
182
183 fmt.doc_comment("Get the controlling type variable operand.");
184 fmt.line("pub fn typevar_operand(&self, pool: &ir::ValueListPool) -> Option<Value> {");
185 fmt.indent(|fmt| {
186 let mut m = Match::new("*self");
187 for format in formats {
188 let name = format!("Self::{}", format.name);
189 if format.typevar_operand.is_none() {
190 m.arm(name, vec![".."], "None".to_string());
191 } else if format.has_value_list {
192 m.arm(name, vec!["ref args", ".."], format!("args.get({}, pool)", format.typevar_operand.unwrap()));
194 } else if format.num_value_operands == 1 {
195 m.arm(name, vec!["arg", ".."], "Some(arg)".to_string());
196 } else {
197 let args = format!("args_arity{}", format.num_value_operands);
200 m.arm(name, vec![format!("args: ref {}", args), "..".to_string()],
201 format!("Some({}[{}])", args, format.typevar_operand.unwrap()));
202 }
203 }
204 fmt.add_match(m);
205 });
206 fmt.line("}");
207 fmt.empty_line();
208
209 fmt.doc_comment("Get the value arguments to this instruction.");
210 gen_arguments_method(formats, fmt, false);
211 fmt.empty_line();
212
213 fmt.doc_comment(r#"Get mutable references to the value arguments to this
214 instruction."#);
215 gen_arguments_method(formats, fmt, true);
216 fmt.empty_line();
217
218 fmt.doc_comment(r#"
219 Take out the value list with all the value arguments and return
220 it.
221
222 This leaves the value list in the instruction empty. Use
223 `put_value_list` to put the value list back.
224 "#);
225 fmt.line("pub fn take_value_list(&mut self) -> Option<ir::ValueList> {");
226 fmt.indent(|fmt| {
227 let mut m = Match::new("*self");
228
229 for format in formats {
230 if format.has_value_list {
231 m.arm(format!("Self::{}", format.name),
232 vec!["ref mut args", ".."],
233 "Some(args.take())".to_string());
234 }
235 }
236
237 m.arm_no_fields("_", "None");
238
239 fmt.add_match(m);
240 });
241 fmt.line("}");
242 fmt.empty_line();
243
244 fmt.doc_comment(r#"
245 Put back a value list.
246
247 After removing a value list with `take_value_list()`, use this
248 method to put it back. It is required that this instruction has
249 a format that accepts a value list, and that the existing value
250 list is empty. This avoids leaking list pool memory.
251 "#);
252 fmt.line("pub fn put_value_list(&mut self, vlist: ir::ValueList) {");
253 fmt.indent(|fmt| {
254 fmt.line("let args = match *self {");
255 fmt.indent(|fmt| {
256 for format in formats {
257 if format.has_value_list {
258 fmtln!(fmt, "Self::{} {{ ref mut args, .. }} => args,", format.name);
259 }
260 }
261 fmt.line("_ => panic!(\"No value list: {:?}\", self),");
262 });
263 fmt.line("};");
264 fmt.line("debug_assert!(args.is_empty(), \"Value list already in use\");");
265 fmt.line("*args = vlist;");
266 });
267 fmt.line("}");
268 fmt.empty_line();
269
270 fmt.doc_comment(r#"
271 Compare two `InstructionData` for equality.
272
273 This operation requires a reference to a `ValueListPool` to
274 determine if the contents of any `ValueLists` are equal.
275 "#);
276 fmt.line("pub fn eq(&self, other: &Self, pool: &ir::ValueListPool) -> bool {");
277 fmt.indent(|fmt| {
278 fmt.line("if ::core::mem::discriminant(self) != ::core::mem::discriminant(other) {");
279 fmt.indent(|fmt| {
280 fmt.line("return false;");
281 });
282 fmt.line("}");
283
284 fmt.line("match (self, other) {");
285 fmt.indent(|fmt| {
286 for format in formats {
287 let name = format!("&Self::{}", format.name);
288 let mut members = vec!["opcode"];
289
290 let args_eq = if format.typevar_operand.is_none() {
291 None
292 } else if format.has_value_list {
293 members.push("args");
294 Some("args1.as_slice(pool) == args2.as_slice(pool)")
295 } else if format.num_value_operands == 1 {
296 members.push("arg");
297 Some("arg1 == arg2")
298 } else {
299 members.push("args");
300 Some("args1 == args2")
301 };
302
303 for field in &format.imm_fields {
304 members.push(field.member);
305 }
306
307 let pat1 = members.iter().map(|x| format!("{}: ref {}1", x, x)).collect::<Vec<_>>().join(", ");
308 let pat2 = members.iter().map(|x| format!("{}: ref {}2", x, x)).collect::<Vec<_>>().join(", ");
309 fmtln!(fmt, "({} {{ {} }}, {} {{ {} }}) => {{", name, pat1, name, pat2);
310 fmt.indent(|fmt| {
311 fmt.line("opcode1 == opcode2");
312 for field in &format.imm_fields {
313 fmtln!(fmt, "&& {}1 == {}2", field.member, field.member);
314 }
315 if let Some(args_eq) = args_eq {
316 fmtln!(fmt, "&& {}", args_eq);
317 }
318 });
319 fmtln!(fmt, "}");
320 }
321 fmt.line("_ => unreachable!()");
322 });
323 fmt.line("}");
324 });
325 fmt.line("}");
326 fmt.empty_line();
327
328 fmt.doc_comment(r#"
329 Hash an `InstructionData`.
330
331 This operation requires a reference to a `ValueListPool` to
332 hash the contents of any `ValueLists`.
333 "#);
334 fmt.line("pub fn hash<H: ::core::hash::Hasher>(&self, state: &mut H, pool: &ir::ValueListPool) {");
335 fmt.indent(|fmt| {
336 fmt.line("match *self {");
337 fmt.indent(|fmt| {
338 for format in formats {
339 let name = format!("Self::{}", format.name);
340 let mut members = vec!["opcode"];
341
342 let args = if format.typevar_operand.is_none() {
343 "&()"
344 } else if format.has_value_list {
345 members.push("ref args");
346 "args.as_slice(pool)"
347 } else if format.num_value_operands == 1 {
348 members.push("ref arg");
349 "arg"
350 } else {
351 members.push("ref args");
352 "args"
353 };
354
355 for field in &format.imm_fields {
356 members.push(field.member);
357 }
358 let members = members.join(", ");
359
360 fmtln!(fmt, "{}{{{}}} => {{", name, members ); fmt.indent(|fmt| {
362 fmt.line("::core::hash::Hash::hash( &::core::mem::discriminant(self), state);");
363 fmt.line("::core::hash::Hash::hash(&opcode, state);");
364 for field in &format.imm_fields {
365 fmtln!(fmt, "::core::hash::Hash::hash(&{}, state);", field.member);
366 }
367 fmtln!(fmt, "::core::hash::Hash::hash({}, state);", args);
368 });
369 fmtln!(fmt, "}");
370 }
371 });
372 fmt.line("}");
373 });
374 fmt.line("}");
375 });
376 fmt.line("}");
377}
378
379fn gen_bool_accessor<T: Fn(&Instruction) -> bool>(
380 all_inst: &AllInstructions,
381 get_attr: T,
382 name: &'static str,
383 doc: &'static str,
384 fmt: &mut Formatter,
385) {
386 fmt.doc_comment(doc);
387 fmtln!(fmt, "pub fn {}(self) -> bool {{", name);
388 fmt.indent(|fmt| {
389 let mut m = Match::new("self");
390 for inst in all_inst.values() {
391 if get_attr(inst) {
392 m.arm_no_fields(format!("Self::{}", inst.camel_name), "true");
393 }
394 }
395 m.arm_no_fields("_", "false");
396 fmt.add_match(m);
397 });
398 fmtln!(fmt, "}");
399 fmt.empty_line();
400}
401
402fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
403 fmt.doc_comment(
404 r#"
405 An instruction opcode.
406
407 All instructions from all supported ISAs are present.
408 "#,
409 );
410 fmt.line("#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]");
411
412 fmt.line("pub enum Opcode {");
417 fmt.indent(|fmt| {
418 let mut is_first_opcode = true;
419 for inst in all_inst.values() {
420 fmt.doc_comment(format!("`{}`. ({})", inst, inst.format.name));
421
422 if let Some(poly) = &inst.polymorphic_info {
424 if poly.use_typevar_operand {
425 let op_num = inst.value_opnums[inst.format.typevar_operand.unwrap()];
426 fmt.doc_comment(format!(
427 "Type inferred from `{}`.",
428 inst.operands_in[op_num].name
429 ));
430 }
431 }
432
433 if is_first_opcode {
435 assert!(inst.opcode_number.index() == 0);
436 fmtln!(fmt, "{} = 1,", inst.camel_name);
438 is_first_opcode = false;
439 } else {
440 fmtln!(fmt, "{},", inst.camel_name)
441 }
442 }
443 });
444 fmt.line("}");
445 fmt.empty_line();
446
447 fmt.line("impl Opcode {");
448 fmt.indent(|fmt| {
449 gen_bool_accessor(
450 all_inst,
451 |inst| inst.is_terminator,
452 "is_terminator",
453 "True for instructions that terminate the EBB",
454 fmt,
455 );
456 gen_bool_accessor(
457 all_inst,
458 |inst| inst.is_branch,
459 "is_branch",
460 "True for all branch or jump instructions.",
461 fmt,
462 );
463 gen_bool_accessor(
464 all_inst,
465 |inst| inst.is_indirect_branch,
466 "is_indirect_branch",
467 "True for all indirect branch or jump instructions.",
468 fmt,
469 );
470 gen_bool_accessor(
471 all_inst,
472 |inst| inst.is_call,
473 "is_call",
474 "Is this a call instruction?",
475 fmt,
476 );
477 gen_bool_accessor(
478 all_inst,
479 |inst| inst.is_return,
480 "is_return",
481 "Is this a return instruction?",
482 fmt,
483 );
484 gen_bool_accessor(
485 all_inst,
486 |inst| inst.is_ghost,
487 "is_ghost",
488 "Is this a ghost instruction?",
489 fmt,
490 );
491 gen_bool_accessor(
492 all_inst,
493 |inst| inst.can_load,
494 "can_load",
495 "Can this instruction read from memory?",
496 fmt,
497 );
498 gen_bool_accessor(
499 all_inst,
500 |inst| inst.can_store,
501 "can_store",
502 "Can this instruction write to memory?",
503 fmt,
504 );
505 gen_bool_accessor(
506 all_inst,
507 |inst| inst.can_trap,
508 "can_trap",
509 "Can this instruction cause a trap?",
510 fmt,
511 );
512 gen_bool_accessor(
513 all_inst,
514 |inst| inst.other_side_effects,
515 "other_side_effects",
516 "Does this instruction have other side effects besides can_* flags?",
517 fmt,
518 );
519 gen_bool_accessor(
520 all_inst,
521 |inst| inst.writes_cpu_flags,
522 "writes_cpu_flags",
523 "Does this instruction write to CPU flags?",
524 fmt,
525 );
526 });
527 fmt.line("}");
528 fmt.empty_line();
529
530 fmtln!(
532 fmt,
533 "const OPCODE_FORMAT: [InstructionFormat; {}] = [",
534 all_inst.len()
535 );
536 fmt.indent(|fmt| {
537 for inst in all_inst.values() {
538 fmtln!(
539 fmt,
540 "InstructionFormat::{}, // {}",
541 inst.format.name,
542 inst.name
543 );
544 }
545 });
546 fmtln!(fmt, "];");
547 fmt.empty_line();
548
549 fmt.line("fn opcode_name(opc: Opcode) -> &\'static str {");
551 fmt.indent(|fmt| {
552 let mut m = Match::new("opc");
553 for inst in all_inst.values() {
554 m.arm_no_fields(
555 format!("Opcode::{}", inst.camel_name),
556 format!("\"{}\"", inst.name),
557 );
558 }
559 fmt.add_match(m);
560 });
561 fmt.line("}");
562 fmt.empty_line();
563
564 let hash_table = constant_hash::generate_table(all_inst.values(), all_inst.len(), |inst| {
566 constant_hash::simple_hash(&inst.name)
567 });
568 fmtln!(
569 fmt,
570 "const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = [",
571 hash_table.len()
572 );
573 fmt.indent(|fmt| {
574 for i in hash_table {
575 match i {
576 Some(i) => fmtln!(fmt, "Some(Opcode::{}),", i.camel_name),
577 None => fmtln!(fmt, "None,"),
578 }
579 }
580 });
581 fmtln!(fmt, "];");
582 fmt.empty_line();
583}
584
585fn get_constraint<'entries, 'table>(
593 operand: &'entries Operand,
594 ctrl_typevar: Option<&TypeVar>,
595 type_sets: &'table mut UniqueTable<'entries, TypeSet>,
596) -> String {
597 assert!(operand.is_value());
598 let type_var = operand.type_var().unwrap();
599
600 if let Some(typ) = type_var.singleton_type() {
601 return format!("Concrete({})", typ.rust_name());
602 }
603
604 if let Some(free_typevar) = type_var.free_typevar() {
605 if ctrl_typevar.is_some() && free_typevar != *ctrl_typevar.unwrap() {
606 assert!(type_var.base.is_none());
607 return format!("Free({})", type_sets.add(&type_var.get_raw_typeset()));
608 }
609 }
610
611 if let Some(base) = &type_var.base {
612 assert!(base.type_var == *ctrl_typevar.unwrap());
613 return camel_case(base.derived_func.name());
614 }
615
616 assert!(type_var == ctrl_typevar.unwrap());
617 "Same".into()
618}
619
620fn gen_bitset<'a, T: IntoIterator<Item = &'a u16>>(
621 iterable: T,
622 name: &'static str,
623 field_size: u8,
624 fmt: &mut Formatter,
625) {
626 let bits = iterable.into_iter().fold(0, |acc, x| {
627 assert!(x.is_power_of_two());
628 assert!(u32::from(*x) < (1 << u32::from(field_size)));
629 acc | x
630 });
631 fmtln!(fmt, "{}: BitSet::<u{}>({}),", name, field_size, bits);
632}
633
634fn iterable_to_string<I: fmt::Display, T: IntoIterator<Item = I>>(iterable: T) -> String {
635 let elems = iterable
636 .into_iter()
637 .map(|x| x.to_string())
638 .collect::<Vec<_>>()
639 .join(", ");
640 format!("{{{}}}", elems)
641}
642
643fn typeset_to_string(ts: &TypeSet) -> String {
644 let mut result = format!("TypeSet(lanes={}", iterable_to_string(&ts.lanes));
645 if !ts.ints.is_empty() {
646 result += &format!(", ints={}", iterable_to_string(&ts.ints));
647 }
648 if !ts.floats.is_empty() {
649 result += &format!(", floats={}", iterable_to_string(&ts.floats));
650 }
651 if !ts.bools.is_empty() {
652 result += &format!(", bools={}", iterable_to_string(&ts.bools));
653 }
654 if !ts.specials.is_empty() {
655 result += &format!(", specials=[{}]", iterable_to_string(&ts.specials));
656 }
657 if !ts.refs.is_empty() {
658 result += &format!(", refs={}", iterable_to_string(&ts.refs));
659 }
660 result += ")";
661 result
662}
663
664pub(crate) fn gen_typesets_table(type_sets: &UniqueTable<TypeSet>, fmt: &mut Formatter) {
666 if type_sets.len() == 0 {
667 return;
668 }
669
670 fmt.comment("Table of value type sets.");
671 assert!(type_sets.len() <= TYPESET_LIMIT, "Too many type sets!");
672 fmtln!(
673 fmt,
674 "const TYPE_SETS: [ir::instructions::ValueTypeSet; {}] = [",
675 type_sets.len()
676 );
677 fmt.indent(|fmt| {
678 for ts in type_sets.iter() {
679 fmt.line("ir::instructions::ValueTypeSet {");
680 fmt.indent(|fmt| {
681 fmt.comment(typeset_to_string(ts));
682 gen_bitset(&ts.lanes, "lanes", 16, fmt);
683 gen_bitset(&ts.ints, "ints", 8, fmt);
684 gen_bitset(&ts.floats, "floats", 8, fmt);
685 gen_bitset(&ts.bools, "bools", 8, fmt);
686 gen_bitset(&ts.refs, "refs", 8, fmt);
687 });
688 fmt.line("},");
689 }
690 });
691 fmtln!(fmt, "];");
692}
693
694fn gen_type_constraints(all_inst: &AllInstructions, fmt: &mut Formatter) {
699 let mut type_sets = UniqueTable::new();
701
702 let mut operand_seqs = UniqueSeqTable::new();
708
709 #[allow(clippy::useless_vec)]
711 operand_seqs.add(&vec!["Same".to_string(); 3]);
712
713 fmt.comment("Table of opcode constraints.");
714 fmtln!(
715 fmt,
716 "const OPCODE_CONSTRAINTS: [OpcodeConstraints; {}] = [",
717 all_inst.len()
718 );
719 fmt.indent(|fmt| {
720 for inst in all_inst.values() {
721 let (ctrl_typevar, ctrl_typeset) = if let Some(poly) = &inst.polymorphic_info {
722 let index = type_sets.add(&*poly.ctrl_typevar.get_raw_typeset());
723 (Some(&poly.ctrl_typevar), index)
724 } else {
725 (None, TYPESET_LIMIT)
726 };
727
728 let mut constraints = Vec::new();
731 for &index in &inst.value_results {
732 constraints.push(get_constraint(&inst.operands_out[index], ctrl_typevar, &mut type_sets));
733 }
734 for &index in &inst.value_opnums {
735 constraints.push(get_constraint(&inst.operands_in[index], ctrl_typevar, &mut type_sets));
736 }
737
738 let constraint_offset = operand_seqs.add(&constraints);
739
740 let fixed_results = inst.value_results.len();
741 let fixed_values = inst.value_opnums.len();
742
743 let use_typevar_operand = if let Some(poly) = &inst.polymorphic_info {
745 poly.use_typevar_operand
746 } else {
747 false
748 };
749
750 let use_result = fixed_results > 0 && inst.operands_out[inst.value_results[0]].type_var() == ctrl_typevar;
752
753 let requires_typevar_operand = use_typevar_operand && !use_result;
755
756 fmt.comment(
757 format!("{}: fixed_results={}, use_typevar_operand={}, requires_typevar_operand={}, fixed_values={}",
758 inst.camel_name,
759 fixed_results,
760 use_typevar_operand,
761 requires_typevar_operand,
762 fixed_values)
763 );
764 fmt.comment(format!("Constraints=[{}]", constraints
765 .iter()
766 .map(|x| format!("'{}'", x))
767 .collect::<Vec<_>>()
768 .join(", ")));
769 if let Some(poly) = &inst.polymorphic_info {
770 fmt.comment(format!("Polymorphic over {}", typeset_to_string(&poly.ctrl_typevar.get_raw_typeset())));
771 }
772
773 assert!(fixed_results < 8 && fixed_values < 8, "Bit field encoding too tight");
775 let mut flags = fixed_results; if use_typevar_operand {
777 flags |= 1<<3; }
779 if requires_typevar_operand {
780 flags |= 1<<4; }
782 flags |= fixed_values << 5; fmt.line("OpcodeConstraints {");
785 fmt.indent(|fmt| {
786 fmtln!(fmt, "flags: {:#04x},", flags);
787 fmtln!(fmt, "typeset_offset: {},", ctrl_typeset);
788 fmtln!(fmt, "constraint_offset: {},", constraint_offset);
789 });
790 fmt.line("},");
791 }
792 });
793 fmtln!(fmt, "];");
794 fmt.empty_line();
795
796 gen_typesets_table(&type_sets, fmt);
797 fmt.empty_line();
798
799 fmt.comment("Table of operand constraint sequences.");
800 fmtln!(
801 fmt,
802 "const OPERAND_CONSTRAINTS: [OperandConstraint; {}] = [",
803 operand_seqs.len()
804 );
805 fmt.indent(|fmt| {
806 for constraint in operand_seqs.iter() {
807 fmtln!(fmt, "OperandConstraint::{},", constraint);
808 }
809 });
810 fmtln!(fmt, "];");
811}
812
813fn gen_member_inits(format: &InstructionFormat, fmt: &mut Formatter) {
815 for f in &format.imm_fields {
818 fmtln!(fmt, "{},", f.member);
819 }
820
821 if format.has_value_list {
823 fmt.line("args,");
824 } else if format.num_value_operands == 1 {
825 fmt.line("arg: arg0,");
826 } else if format.num_value_operands > 1 {
827 let mut args = Vec::new();
828 for i in 0..format.num_value_operands {
829 args.push(format!("arg{}", i));
830 }
831 fmtln!(fmt, "args: [{}],", args.join(", "));
832 }
833}
834
835fn gen_format_constructor(format: &InstructionFormat, fmt: &mut Formatter) {
840 let mut args = vec![
842 "self".to_string(),
843 "opcode: Opcode".into(),
844 "ctrl_typevar: Type".into(),
845 ];
846
847 for f in &format.imm_fields {
849 args.push(format!("{}: {}", f.member, f.kind.rust_type));
850 }
851
852 if format.has_value_list {
854 args.push("args: ir::ValueList".into());
857 } else {
858 for i in 0..format.num_value_operands {
860 args.push(format!("arg{}: Value", i));
861 }
862 }
863
864 let proto = format!(
865 "{}({}) -> (Inst, &'f mut ir::DataFlowGraph)",
866 format.name,
867 args.join(", ")
868 );
869
870 fmt.doc_comment(format.to_string());
871 fmt.line("#[allow(non_snake_case)]");
872 fmtln!(fmt, "fn {} {{", proto);
873 fmt.indent(|fmt| {
874 fmtln!(fmt, "let data = ir::InstructionData::{} {{", format.name);
876 fmt.indent(|fmt| {
877 fmt.line("opcode,");
878 gen_member_inits(format, fmt);
879 });
880 fmtln!(fmt, "};");
881 fmt.line("self.build(data, ctrl_typevar)");
882 });
883 fmtln!(fmt, "}");
884}
885
886fn gen_inst_builder(inst: &Instruction, format: &InstructionFormat, fmt: &mut Formatter) {
891 let mut args = vec![if format.has_value_list {
893 "mut self"
894 } else {
895 "self"
896 }
897 .to_string()];
898
899 let mut args_doc = Vec::new();
900 let mut rets_doc = Vec::new();
901
902 if let Some(poly) = &inst.polymorphic_info {
905 if !poly.use_typevar_operand {
906 args.push(format!("{}: crate::ir::Type", poly.ctrl_typevar.name));
907 args_doc.push(format!(
908 "- {} (controlling type variable): {}",
909 poly.ctrl_typevar.name, poly.ctrl_typevar.doc
910 ));
911 }
912 }
913
914 let mut tmpl_types = Vec::new();
915 let mut into_args = Vec::new();
916 for op in &inst.operands_in {
917 let t = if op.is_immediate() {
918 let t = format!("T{}", tmpl_types.len() + 1);
919 tmpl_types.push(format!("{}: Into<{}>", t, op.kind.rust_type));
920 into_args.push(op.name);
921 t
922 } else {
923 op.kind.rust_type.to_string()
924 };
925 args.push(format!("{}: {}", op.name, t));
926 args_doc.push(format!(
927 "- {}: {}",
928 op.name,
929 op.doc()
930 .expect("every instruction's input operand must be documented")
931 ));
932 }
933
934 for op in &inst.operands_out {
935 rets_doc.push(format!(
936 "- {}: {}",
937 op.name,
938 op.doc()
939 .expect("every instruction's output operand must be documented")
940 ));
941 }
942
943 let rtype = match inst.value_results.len() {
944 0 => "Inst".into(),
945 1 => "Value".into(),
946 _ => format!("({})", vec!["Value"; inst.value_results.len()].join(", ")),
947 };
948
949 let tmpl = if !tmpl_types.is_empty() {
950 format!("<{}>", tmpl_types.join(", "))
951 } else {
952 "".into()
953 };
954
955 let proto = format!(
956 "{}{}({}) -> {}",
957 inst.snake_name(),
958 tmpl,
959 args.join(", "),
960 rtype
961 );
962
963 fmt.doc_comment(&inst.doc);
964 if !args_doc.is_empty() {
965 fmt.line("///");
966 fmt.doc_comment("Inputs:");
967 fmt.line("///");
968 for doc_line in args_doc {
969 fmt.doc_comment(doc_line);
970 }
971 }
972 if !rets_doc.is_empty() {
973 fmt.line("///");
974 fmt.doc_comment("Outputs:");
975 fmt.line("///");
976 for doc_line in rets_doc {
977 fmt.doc_comment(doc_line);
978 }
979 }
980
981 fmt.line("#[allow(non_snake_case)]");
982 fmtln!(fmt, "fn {} {{", proto);
983 fmt.indent(|fmt| {
984 for arg in &into_args {
986 fmtln!(fmt, "let {} = {}.into();", arg, arg);
987 }
988
989 let first_arg = format!("Opcode::{}", inst.camel_name);
991 let mut args = vec![first_arg.as_str()];
992 if let Some(poly) = &inst.polymorphic_info {
993 if poly.use_typevar_operand {
994 let op_num = inst.value_opnums[format.typevar_operand.unwrap()];
996 fmtln!(
997 fmt,
998 "let ctrl_typevar = self.data_flow_graph().value_type({});",
999 inst.operands_in[op_num].name
1000 );
1001
1002 args.push("ctrl_typevar");
1004 } else {
1005 args.push(&poly.ctrl_typevar.name);
1007 }
1008 } else {
1009 args.push("types::INVALID");
1011 }
1012
1013 for &op_num in &inst.imm_opnums {
1015 args.push(inst.operands_in[op_num].name);
1016 }
1017
1018 if format.has_value_list {
1020 fmt.line("let mut vlist = ir::ValueList::default();");
1022 args.push("vlist");
1023 fmt.line("{");
1024 fmt.indent(|fmt| {
1025 fmt.line("let pool = &mut self.data_flow_graph_mut().value_lists;");
1026 for op in &inst.operands_in {
1027 if op.is_value() {
1028 fmtln!(fmt, "vlist.push({}, pool);", op.name);
1029 } else if op.is_varargs() {
1030 fmtln!(fmt, "vlist.extend({}.iter().cloned(), pool);", op.name);
1031 }
1032 }
1033 });
1034 fmt.line("}");
1035 } else {
1036 for &op_num in &inst.value_opnums {
1038 args.push(inst.operands_in[op_num].name);
1039 }
1040 }
1041
1042 let fcall = format!("self.{}({})", format.name, args.join(", "));
1044
1045 if inst.value_results.is_empty() {
1046 fmtln!(fmt, "{}.0", fcall);
1047 return;
1048 }
1049
1050 fmtln!(fmt, "let (inst, dfg) = {};", fcall);
1051 if inst.value_results.len() == 1 {
1052 fmt.line("dfg.first_result(inst)");
1053 } else {
1054 fmtln!(
1055 fmt,
1056 "let results = &dfg.inst_results(inst)[0..{}];",
1057 inst.value_results.len()
1058 );
1059 fmtln!(
1060 fmt,
1061 "({})",
1062 inst.value_results
1063 .iter()
1064 .enumerate()
1065 .map(|(i, _)| format!("results[{}]", i))
1066 .collect::<Vec<_>>()
1067 .join(", ")
1068 );
1069 }
1070 });
1071 fmtln!(fmt, "}")
1072}
1073
1074fn gen_builder(
1076 instructions: &AllInstructions,
1077 formats: &[&InstructionFormat],
1078 fmt: &mut Formatter,
1079) {
1080 fmt.doc_comment(
1081 r#"
1082 Convenience methods for building instructions.
1083
1084 The `InstBuilder` trait has one method per instruction opcode for
1085 conveniently constructing the instruction with minimum arguments.
1086 Polymorphic instructions infer their result types from the input
1087 arguments when possible. In some cases, an explicit `ctrl_typevar`
1088 argument is required.
1089
1090 The opcode methods return the new instruction's result values, or
1091 the `Inst` itself for instructions that don't have any results.
1092
1093 There is also a method per instruction format. These methods all
1094 return an `Inst`.
1095 "#,
1096 );
1097 fmt.line("pub trait InstBuilder<'f>: InstBuilderBase<'f> {");
1098 fmt.indent(|fmt| {
1099 for inst in instructions.values() {
1100 gen_inst_builder(inst, &*inst.format, fmt);
1101 fmt.empty_line();
1102 }
1103 for (i, format) in formats.iter().enumerate() {
1104 gen_format_constructor(format, fmt);
1105 if i + 1 != formats.len() {
1106 fmt.empty_line();
1107 }
1108 }
1109 });
1110 fmt.line("}");
1111}
1112
1113pub(crate) fn generate(
1114 formats: Vec<&InstructionFormat>,
1115 all_inst: &AllInstructions,
1116 opcode_filename: &str,
1117 inst_builder_filename: &str,
1118 out_dir: &str,
1119) -> Result<(), error::Error> {
1120 let mut fmt = Formatter::new();
1122 gen_formats(&formats, &mut fmt);
1123 gen_instruction_data(&formats, &mut fmt);
1124 fmt.empty_line();
1125 gen_instruction_data_impl(&formats, &mut fmt);
1126 fmt.empty_line();
1127 gen_opcodes(all_inst, &mut fmt);
1128 gen_type_constraints(all_inst, &mut fmt);
1129 fmt.update_file(opcode_filename, out_dir)?;
1130
1131 let mut fmt = Formatter::new();
1133 gen_builder(all_inst, &formats, &mut fmt);
1134 fmt.update_file(inst_builder_filename, out_dir)?;
1135
1136 Ok(())
1137}