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