1 //! Contains the code-generation logic to emit for the DSL-defined instructions. 2 3 mod features; 4 mod format; 5 mod inst; 6 mod operand; 7 8 use crate::dsl; 9 use cranelift_srcgen::{Formatter, fmtln}; 10 11 /// Generate the Rust assembler code; e.g., `enum Inst { ... }`. 12 pub fn rust_assembler(f: &mut Formatter, insts: &[dsl::Inst]) { 13 // Generate "all instructions" enum. 14 generate_inst_enum(f, insts); 15 generate_inst_display_impl(f, insts); 16 generate_inst_encode_impl(f, insts); 17 generate_inst_visit_impl(f, insts); 18 generate_inst_is_available_impl(f, insts); 19 generate_inst_features_impl(f, insts); 20 21 // Generate per-instruction structs. 22 f.empty_line(); 23 for inst in insts { 24 inst.generate_struct(f); 25 inst.generate_struct_impl(f); 26 inst.generate_display_impl(f); 27 inst.generate_from_impl(f); 28 f.empty_line(); 29 } 30 31 // Generate the `Feature` trait. 32 dsl::Feature::generate_macro(f); 33 } 34 35 /// `enum Inst { ... }` 36 fn generate_inst_enum(f: &mut Formatter, insts: &[dsl::Inst]) { 37 fmtln!(f, "#[doc(hidden)]"); 38 generate_derive(f); 39 generate_derive_arbitrary_bounds(f); 40 f.add_block("pub enum Inst<R: Registers>", |f| { 41 for inst in insts { 42 let variant_name = inst.name(); 43 let struct_name = inst.struct_name_with_generic(); 44 fmtln!(f, "{variant_name}({struct_name}),"); 45 } 46 }); 47 } 48 49 /// `#[derive(...)]` 50 fn generate_derive(f: &mut Formatter) { 51 fmtln!(f, "#[derive(Copy, Clone, Debug)]"); 52 fmtln!( 53 f, 54 "#[cfg_attr(any(test, feature = \"fuzz\"), derive(arbitrary::Arbitrary))]" 55 ); 56 } 57 58 /// Adds a custom bound to the `Arbitrary` implementation which ensures that 59 /// the associated registers are all `Arbitrary` as well. 60 fn generate_derive_arbitrary_bounds(f: &mut Formatter) { 61 fmtln!( 62 f, 63 "#[cfg_attr(any(test, feature = \"fuzz\"), arbitrary(bound = \"R: crate::fuzz::RegistersArbitrary\"))]" 64 ); 65 } 66 67 /// `impl std::fmt::Display for Inst { ... }` 68 fn generate_inst_display_impl(f: &mut Formatter, insts: &[dsl::Inst]) { 69 f.add_block("impl<R: Registers> std::fmt::Display for Inst<R>", |f| { 70 f.add_block( 71 "fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result", 72 |f| { 73 f.add_block("match self", |f| { 74 for inst in insts { 75 let variant_name = inst.name(); 76 fmtln!(f, "Self::{variant_name}(i) => i.fmt(f),"); 77 } 78 }); 79 }, 80 ); 81 }); 82 } 83 84 /// `impl Inst { fn encode... }` 85 fn generate_inst_encode_impl(f: &mut Formatter, insts: &[dsl::Inst]) { 86 f.add_block("impl<R: Registers> Inst<R>", |f| { 87 f.add_block("pub fn encode(&self, b: &mut impl CodeSink)", |f| { 88 f.add_block("match self", |f| { 89 for inst in insts { 90 let variant_name = inst.name(); 91 fmtln!(f, "Self::{variant_name}(i) => i.encode(b),"); 92 } 93 }); 94 }); 95 }); 96 } 97 98 /// `impl Inst { fn visit... }` 99 fn generate_inst_visit_impl(f: &mut Formatter, insts: &[dsl::Inst]) { 100 fmtln!(f, "impl<R: Registers> Inst<R> {{"); 101 f.indent(|f| { 102 fmtln!( 103 f, 104 "pub fn visit(&mut self, v: &mut impl RegisterVisitor<R>) {{" 105 ); 106 f.indent(|f| { 107 fmtln!(f, "match self {{"); 108 f.indent_push(); 109 for inst in insts { 110 let variant_name = inst.name(); 111 fmtln!(f, "Self::{variant_name}(i) => i.visit(v),"); 112 } 113 f.indent_pop(); 114 fmtln!(f, "}}"); 115 }); 116 fmtln!(f, "}}"); 117 }); 118 fmtln!(f, "}}"); 119 } 120 121 /// `impl Inst { fn is_available... }` 122 fn generate_inst_is_available_impl(f: &mut Formatter, insts: &[dsl::Inst]) { 123 f.add_block("impl<R: Registers> Inst<R>", |f| { 124 f.add_block( 125 "pub fn is_available(&self, f: &impl AvailableFeatures) -> bool", 126 |f| { 127 f.add_block("match self", |f| { 128 for inst in insts { 129 let variant_name = inst.name(); 130 fmtln!(f, "Self::{variant_name}(i) => i.is_available(f),"); 131 } 132 }); 133 }, 134 ); 135 }); 136 } 137 138 /// `impl Inst { fn features... }` 139 fn generate_inst_features_impl(f: &mut Formatter, insts: &[dsl::Inst]) { 140 f.add_block("impl<R: Registers> Inst<R>", |f| { 141 f.add_block("pub fn features(&self) -> &'static Features", |f| { 142 f.add_block("match self", |f| { 143 for inst in insts { 144 let variant_name = inst.name(); 145 fmtln!(f, "Self::{variant_name}(i) => i.features(),"); 146 } 147 }); 148 }); 149 }); 150 } 151