Skip to content

Commit 3a13642

Browse files
authored
asm: add num_registers_available() (#11714)
This change adds a way to inspect how many registers an instruction can address. We assume for now that legacy instructions can always emit the REX prefix and thus access 16 registers; thus, the only encoding that allows access to 32 registers is EVEX. This also refactors some of the top-level generation logic to be less verbose.
1 parent c3b1004 commit 3a13642

File tree

2 files changed

+55
-80
lines changed

2 files changed

+55
-80
lines changed

cranelift/assembler-x64/meta/src/generate.rs

Lines changed: 40 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@ use cranelift_srcgen::{Formatter, fmtln};
1212
pub fn rust_assembler(f: &mut Formatter, insts: &[dsl::Inst]) {
1313
// Generate "all instructions" enum.
1414
generate_inst_enum(f, insts);
15+
generate_inst_impls(f, insts);
1516
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);
2017

2118
// Generate per-instruction structs.
2219
f.empty_line();
@@ -46,22 +43,14 @@ fn generate_inst_enum(f: &mut Formatter, insts: &[dsl::Inst]) {
4643
});
4744
}
4845

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-
);
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+
});
6554
}
6655

6756
/// `impl std::fmt::Display for Inst { ... }`
@@ -70,81 +59,52 @@ fn generate_inst_display_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
7059
f.add_block(
7160
"fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result",
7261
|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-
});
62+
match_variants(f, insts, "fmt(f)");
7963
},
8064
);
8165
});
8266
}
8367

84-
/// `impl Inst { fn encode... }`
85-
fn generate_inst_encode_impl(f: &mut Formatter, insts: &[dsl::Inst]) {
68+
fn generate_inst_impls(f: &mut Formatter, insts: &[dsl::Inst]) {
8669
f.add_block("impl<R: Registers> Inst<R>", |f| {
8770
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-
});
71+
match_variants(f, insts, "encode(b)");
9472
});
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>) {{"
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+
},
10578
);
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| {
12479
f.add_block(
12580
"pub fn is_available(&self, f: &impl AvailableFeatures) -> bool",
12681
|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-
});
82+
match_variants(f, insts, "is_available(f)");
13383
},
13484
);
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| {
14185
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-
});
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()");
14890
});
14991
});
15092
}
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+
}

cranelift/assembler-x64/meta/src/generate/inst.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ impl dsl::Inst {
6868
self.generate_is_available_function(f);
6969
f.empty_line();
7070
self.generate_features_function(f);
71+
f.empty_line();
72+
self.generate_num_registers_function(f);
7173
});
7274
}
7375

@@ -244,6 +246,19 @@ impl dsl::Inst {
244246
});
245247
}
246248

249+
/// `fn num_registers_available(&self) -> usize { ... }`
250+
fn generate_num_registers_function(&self, f: &mut Formatter) {
251+
fmtln!(f, "#[must_use]");
252+
f.add_block("pub fn num_registers_available(&self) -> usize", |f| {
253+
use dsl::Encoding::*;
254+
let n = match self.encoding {
255+
Rex(_) | Vex(_) => 16,
256+
Evex(_) => 32,
257+
};
258+
fmtln!(f, "{n}")
259+
});
260+
}
261+
247262
/// `impl Display for <inst> { ... }`
248263
pub fn generate_display_impl(&self, f: &mut Formatter) {
249264
use crate::dsl::Customization::*;

0 commit comments

Comments
 (0)