Path: blob/main/cranelift/assembler-x64/meta/src/generate.rs
3088 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_impls(f, insts);15generate_inst_display_impl(f, insts);1617// Generate per-instruction structs.18f.empty_line();19for inst in insts {20inst.generate_struct(f);21inst.generate_struct_impl(f);22inst.generate_display_impl(f);23inst.generate_from_impl(f);24f.empty_line();25}2627// Generate the `Feature` trait.28dsl::Feature::generate_macro(f);29}3031/// `enum Inst { ... }`32fn generate_inst_enum(f: &mut Formatter, insts: &[dsl::Inst]) {33fmtln!(f, "#[doc(hidden)]");34generate_derive(f);35generate_derive_arbitrary_bounds(f);36f.add_block("pub enum Inst<R: Registers>", |f| {37for inst in insts {38let variant_name = inst.name();39let struct_name = inst.struct_name_with_generic();40fmtln!(f, "{variant_name}({struct_name}),");41}42});43}4445/// Helper for emitting `match self { ... }` blocks over all instructions. For each instruction in46/// `insts`, this generate a separate match arm containing `invoke`.47fn match_variants(f: &mut Formatter, insts: &[dsl::Inst], invoke: &str) {48f.add_block("match self", |f| {49for inst in insts.iter().map(|i| i.name()) {50fmtln!(f, "Self::{inst}(i) => i.{invoke},");51}52});53}5455/// `impl core::fmt::Display for Inst { ... }`56fn generate_inst_display_impl(f: &mut Formatter, insts: &[dsl::Inst]) {57f.add_block("impl<R: Registers> core::fmt::Display for Inst<R>", |f| {58f.add_block(59"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result",60|f| {61match_variants(f, insts, "fmt(f)");62},63);64});65}6667fn generate_inst_impls(f: &mut Formatter, insts: &[dsl::Inst]) {68f.add_block("impl<R: Registers> Inst<R>", |f| {69f.add_block("pub fn encode(&self, b: &mut impl CodeSink)", |f| {70match_variants(f, insts, "encode(b)");71});72f.add_block(73"pub fn visit(&mut self, v: &mut impl RegisterVisitor<R>)",74|f| {75match_variants(f, insts, "visit(v)");76},77);78f.add_block(79"pub fn is_available(&self, f: &impl AvailableFeatures) -> bool",80|f| {81match_variants(f, insts, "is_available(f)");82},83);84f.add_block("pub fn features(&self) -> &'static Features", |f| {85match_variants(f, insts, "features()");86});87f.add_block("pub fn num_registers_available(&self) -> usize", |f| {88match_variants(f, insts, "num_registers_available()");89});90});91}9293/// `#[derive(...)]`94fn generate_derive(f: &mut Formatter) {95fmtln!(f, "#[derive(Copy, Clone, Debug)]");96fmtln!(97f,98"#[cfg_attr(any(test, feature = \"fuzz\"), derive(arbitrary::Arbitrary))]"99);100}101102/// Adds a custom bound to the `Arbitrary` implementation which ensures that103/// the associated registers are all `Arbitrary` as well.104fn generate_derive_arbitrary_bounds(f: &mut Formatter) {105fmtln!(106f,107"#[cfg_attr(any(test, feature = \"fuzz\"), arbitrary(bound = \"R: crate::fuzz::RegistersArbitrary\"))]"108);109}110111112