Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/meta/src/generate/inst.rs
1693 views
1
use super::{Formatter, fmtln, generate_derive, generate_derive_arbitrary_bounds};
2
use crate::dsl;
3
4
impl dsl::Inst {
5
/// `struct <inst> { <op>: Reg, <op>: Reg, ... }`
6
pub fn generate_struct(&self, f: &mut Formatter) {
7
let struct_name = self.struct_name_with_generic();
8
let where_clause = if self.requires_generic() {
9
"where R: Registers"
10
} else {
11
""
12
};
13
14
fmtln!(f, "/// `{self}`");
15
generate_derive(f);
16
if self.requires_generic() {
17
generate_derive_arbitrary_bounds(f);
18
}
19
f.add_block(&format!("pub struct {struct_name} {where_clause}"), |f| {
20
for k in &self.format.operands {
21
let loc = k.location;
22
let ty = k.generate_type();
23
fmtln!(f, "pub {loc}: {ty},");
24
}
25
26
if self.has_trap {
27
fmtln!(f, "pub trap: TrapCode,");
28
}
29
});
30
}
31
32
fn requires_generic(&self) -> bool {
33
self.format.uses_register()
34
}
35
36
/// `<struct_name><R>`
37
pub(crate) fn struct_name_with_generic(&self) -> String {
38
let struct_name = self.name();
39
if self.requires_generic() {
40
format!("{struct_name}<R>")
41
} else {
42
struct_name
43
}
44
}
45
46
/// `impl...`
47
fn generate_impl_block_start(&self) -> &str {
48
if self.requires_generic() {
49
"impl<R: Registers>"
50
} else {
51
"impl"
52
}
53
}
54
55
/// `impl <inst> { ... }`
56
pub fn generate_struct_impl(&self, f: &mut Formatter) {
57
let impl_block = self.generate_impl_block_start();
58
let struct_name = self.struct_name_with_generic();
59
f.add_block(&format!("{impl_block} {struct_name}"), |f| {
60
self.generate_new_function(f);
61
f.empty_line();
62
self.generate_mnemonic_function(f);
63
f.empty_line();
64
self.generate_encode_function(f);
65
f.empty_line();
66
self.generate_visit_function(f);
67
f.empty_line();
68
self.generate_is_available_function(f);
69
f.empty_line();
70
self.generate_features_function(f);
71
});
72
}
73
74
// `fn new(<params>) -> Self { ... }`
75
pub fn generate_new_function(&self, f: &mut Formatter) {
76
let params = comma_join(
77
self.format
78
.operands
79
.iter()
80
.map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type()))
81
.chain(if self.has_trap {
82
Some("trap: impl Into<TrapCode>".to_string())
83
} else {
84
None
85
}),
86
);
87
fmtln!(f, "#[must_use]");
88
f.add_block(&format!("pub fn new({params}) -> Self"), |f| {
89
f.add_block("Self", |f| {
90
for o in &self.format.operands {
91
let loc = o.location;
92
fmtln!(f, "{loc}: {loc}.into(),");
93
}
94
if self.has_trap {
95
fmtln!(f, "trap: trap.into(),");
96
}
97
});
98
});
99
}
100
101
/// `fn mnemonic(&self) -> &'static str { ... }`
102
pub fn generate_mnemonic_function(&self, f: &mut Formatter) {
103
use dsl::Customization::*;
104
105
fmtln!(f, "#[must_use]");
106
fmtln!(f, "#[inline]");
107
f.add_block(
108
&format!("pub fn mnemonic(&self) -> std::borrow::Cow<'static, str>"),
109
|f| {
110
if self.custom.contains(Mnemonic) {
111
fmtln!(f, "crate::custom::mnemonic::{}(self)", self.name());
112
} else {
113
fmtln!(f, "std::borrow::Cow::Borrowed(\"{}\")", self.mnemonic);
114
}
115
},
116
);
117
}
118
119
/// `fn encode(&self, ...) { ... }`
120
fn generate_encode_function(&self, f: &mut Formatter) {
121
use dsl::Customization::*;
122
123
f.add_block(
124
&format!("pub fn encode(&self, buf: &mut impl CodeSink)"),
125
|f| {
126
if self.custom.contains(Encode) {
127
fmtln!(f, "crate::custom::encode::{}(self, buf);", self.name());
128
} else {
129
self.generate_possible_trap(f);
130
match &self.encoding {
131
dsl::Encoding::Rex(rex) => self.format.generate_rex_encoding(f, rex),
132
dsl::Encoding::Vex(vex) => self.format.generate_vex_encoding(f, vex),
133
dsl::Encoding::Evex(evex) => self.format.generate_evex_encoding(f, evex),
134
}
135
}
136
},
137
);
138
}
139
140
// `buf.add_trap(...)`
141
fn generate_possible_trap(&self, f: &mut Formatter) {
142
if self.has_trap {
143
f.comment("Emit trap.");
144
fmtln!(f, "buf.add_trap(self.trap);");
145
} else if let Some(op) = self.format.uses_memory() {
146
use dsl::OperandKind::*;
147
f.comment("Emit trap.");
148
match op.kind() {
149
Mem(_) => {
150
f.add_block(
151
&format!("if let Some(trap_code) = self.{op}.trap_code()"),
152
|f| {
153
fmtln!(f, "buf.add_trap(trap_code);");
154
},
155
);
156
}
157
RegMem(_) => {
158
let ty = op.reg_class().unwrap();
159
f.add_block(&format!("if let {ty}Mem::Mem({op}) = &self.{op}"), |f| {
160
f.add_block(&format!("if let Some(trap_code) = {op}.trap_code()"), |f| {
161
fmtln!(f, "buf.add_trap(trap_code);");
162
});
163
});
164
}
165
_ => unreachable!(),
166
}
167
}
168
}
169
170
/// `fn visit(&self, ...) { ... }`
171
fn generate_visit_function(&self, f: &mut Formatter) {
172
use dsl::{Customization::*, OperandKind::*};
173
let extra_generic_bound = if self.requires_generic() {
174
""
175
} else {
176
"<R: Registers>"
177
};
178
let visitor = if self.format.operands.is_empty() && !self.custom.contains(Visit) {
179
"_"
180
} else {
181
"visitor"
182
};
183
f.add_block(&format!("pub fn visit{extra_generic_bound}(&mut self, {visitor}: &mut impl RegisterVisitor<R>)"), |f| {
184
if self.custom.contains(Visit) {
185
fmtln!(f, "crate::custom::visit::{}(self, visitor)", self.name());
186
return;
187
}
188
for o in &self.format.operands {
189
let mutability = o.mutability.generate_snake_case();
190
let reg = o.location.reg_class();
191
match o.location.kind() {
192
Imm(_) => {
193
// Immediates do not need register allocation.
194
//
195
// If an instruction happens to only have immediates
196
// then generate a dummy use of the `visitor` variable
197
// to suppress unused variables warnings.
198
fmtln!(f, "let _ = visitor;");
199
}
200
FixedReg(loc) => {
201
let reg_lower = reg.unwrap().to_string().to_lowercase();
202
fmtln!(f, "let enc = self.{loc}.expected_enc();");
203
fmtln!(f, "visitor.fixed_{mutability}_{reg_lower}(&mut self.{loc}.0, enc);");
204
}
205
Reg(loc) => {
206
let reg_lower = reg.unwrap().to_string().to_lowercase();
207
fmtln!(f, "visitor.{mutability}_{reg_lower}(self.{loc}.as_mut());");
208
}
209
RegMem(loc) => {
210
let reg = reg.unwrap();
211
let reg_lower = reg.to_string().to_lowercase();
212
fmtln!(f, "visitor.{mutability}_{reg_lower}_mem(&mut self.{loc});");
213
}
214
Mem(loc) => {
215
// Note that this is always "read" because from a
216
// regalloc perspective when using an amode it means
217
// that the while a write is happening that's to
218
// memory, not registers.
219
fmtln!(f, "visitor.read_amode(&mut self.{loc});");
220
}
221
222
}
223
}
224
});
225
}
226
227
/// `fn is_available(&self, ...) -> bool { ... }`
228
fn generate_is_available_function(&self, f: &mut Formatter) {
229
fmtln!(f, "#[must_use]");
230
f.add_block(
231
"pub fn is_available(&self, features: &impl AvailableFeatures) -> bool",
232
|f| {
233
let expr = self.features.generate_boolean_expr("features");
234
fmtln!(f, "{expr}");
235
},
236
);
237
}
238
239
/// `fn features(&self) -> Features { ... }`
240
fn generate_features_function(&self, f: &mut Formatter) {
241
fmtln!(f, "#[must_use]");
242
f.add_block("pub fn features(&self) -> &'static Features", |f| {
243
self.features.generate_constructor_expr(f);
244
});
245
}
246
247
/// `impl Display for <inst> { ... }`
248
pub fn generate_display_impl(&self, f: &mut Formatter) {
249
use crate::dsl::Customization::*;
250
let impl_block = self.generate_impl_block_start();
251
let struct_name = self.struct_name_with_generic();
252
f.add_block(
253
&format!("{impl_block} std::fmt::Display for {struct_name}"),
254
|f| {
255
f.add_block(
256
"fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result",
257
|f| {
258
if self.custom.contains(Display) {
259
fmtln!(f, "crate::custom::display::{}(f, self)", self.name());
260
return;
261
}
262
263
fmtln!(f, "let name = self.mnemonic();");
264
if self.format.operands.is_empty() {
265
fmtln!(f, "f.write_str(&name)");
266
return;
267
}
268
for op in self.format.operands.iter() {
269
let location = op.location;
270
let to_string = location.generate_to_string(op.extension);
271
fmtln!(f, "let {location} = {to_string};");
272
}
273
let ordered_ops = self.format.generate_att_style_operands();
274
let mut implicit_ops = self.format.generate_implicit_operands();
275
if self.has_trap {
276
fmtln!(f, "let trap = self.trap;");
277
if implicit_ops.is_empty() {
278
implicit_ops.push_str(" ;; {trap}");
279
} else {
280
implicit_ops.push_str(", {trap}");
281
}
282
}
283
fmtln!(f, "write!(f, \"{{name}} {ordered_ops}{implicit_ops}\")");
284
},
285
);
286
},
287
);
288
}
289
290
/// `impl From<struct> for Inst { ... }`
291
pub fn generate_from_impl(&self, f: &mut Formatter) {
292
let struct_name_r = self.struct_name_with_generic();
293
let variant_name = self.name();
294
f.add_block(
295
&format!("impl<R: Registers> From<{struct_name_r}> for Inst<R>"),
296
|f| {
297
f.add_block(&format!("fn from(inst: {struct_name_r}) -> Self"), |f| {
298
fmtln!(f, "Self::{variant_name}(inst)");
299
});
300
},
301
);
302
}
303
}
304
305
fn comma_join<S: Into<String>>(items: impl Iterator<Item = S>) -> String {
306
items.map(Into::into).collect::<Vec<_>>().join(", ")
307
}
308
309