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