Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/meta/src/gen_settings.rs
1692 views
1
//! Generate the ISA-specific settings.
2
3
use crate::cdsl::camel_case;
4
use crate::cdsl::settings::{
5
BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
6
};
7
use crate::constant_hash::generate_table;
8
use crate::unique_table::UniqueSeqTable;
9
use cranelift_codegen_shared::constant_hash::simple_hash;
10
use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};
11
use std::collections::HashMap;
12
13
pub(crate) enum ParentGroup {
14
None,
15
Shared,
16
}
17
18
/// Emits the constructor of the Flags structure.
19
fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
20
let args = match parent {
21
ParentGroup::None => "builder: Builder",
22
ParentGroup::Shared => "shared: &settings::Flags, builder: &Builder",
23
};
24
fmt.add_block("impl Flags", |fmt| {
25
fmt.doc_comment(format!("Create flags {} settings group.", group.name));
26
fmtln!(
27
fmt,
28
"#[allow(unused_variables, reason = \"generated code\")]"
29
);
30
fmt.add_block(&format!("pub fn new({args}) -> Self"), |fmt| {
31
fmtln!(fmt, "let bvec = builder.state_for(\"{}\");", group.name);
32
fmtln!(
33
fmt,
34
"let mut {} = Self {{ bytes: [0; {}] }};",
35
group.name,
36
group.byte_size()
37
);
38
fmtln!(
39
fmt,
40
"debug_assert_eq!(bvec.len(), {});",
41
group.settings_size
42
);
43
fmtln!(
44
fmt,
45
"{}.bytes[0..{}].copy_from_slice(&bvec);",
46
group.name,
47
group.settings_size
48
);
49
50
// Now compute the predicates.
51
for p in &group.predicates {
52
fmt.comment(format!("Precompute #{}.", p.number));
53
fmt.add_block(&format!("if {}", p.render(group)), |fmt| {
54
fmtln!(
55
fmt,
56
"{}.bytes[{}] |= 1 << {};",
57
group.name,
58
group.bool_start_byte_offset + p.number / 8,
59
p.number % 8
60
);
61
});
62
}
63
64
fmtln!(fmt, "{}", group.name);
65
});
66
});
67
}
68
69
/// Generates the `iter` function.
70
fn gen_iterator(group: &SettingGroup, fmt: &mut Formatter) {
71
fmt.add_block("impl Flags",|fmt| {
72
fmt.doc_comment("Iterates the setting values.");
73
fmt.add_block("pub fn iter(&self) -> impl Iterator<Item = Value> + use<>",|fmt| {
74
fmtln!(fmt, "let mut bytes = [0; {}];", group.settings_size);
75
fmtln!(fmt, "bytes.copy_from_slice(&self.bytes[0..{}]);", group.settings_size);
76
fmt.add_block("DESCRIPTORS.iter().filter_map(move |d|", |fmt| {
77
fmt.add_block("let values = match &d.detail", |fmt| {
78
fmtln!(fmt, "detail::Detail::Preset => return None,");
79
fmtln!(fmt, "detail::Detail::Enum {{ last, enumerators }} => Some(TEMPLATE.enums(*last, *enumerators)),");
80
fmtln!(fmt, "_ => None");
81
});
82
fmtln!(fmt, ";");
83
fmtln!(fmt, "Some(Value {{ name: d.name, detail: d.detail, values, value: bytes[d.offset as usize] }})");
84
});
85
fmtln!(fmt, ")");
86
});
87
});
88
}
89
90
/// Generates a `all()` function with all options for this enum
91
fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) {
92
fmtln!(
93
fmt,
94
"/// Returns a slice with all possible [{}] values.",
95
name
96
);
97
fmt.add_block(&format!("pub fn all() -> &'static [{name}]"), |fmt| {
98
fmtln!(fmt, "&[");
99
fmt.indent(|fmt| {
100
for v in values.iter() {
101
fmtln!(fmt, "Self::{},", camel_case(v));
102
}
103
});
104
fmtln!(fmt, "]");
105
});
106
}
107
108
/// Emit Display and FromStr implementations for enum settings.
109
fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {
110
fmt.add_block(&format!("impl fmt::Display for {name}"), |fmt| {
111
fmt.add_block(
112
"fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",
113
|fmt| {
114
fmt.add_block("f.write_str(match *self", |fmt| {
115
for v in values.iter() {
116
fmtln!(fmt, "Self::{} => \"{}\",", camel_case(v), v);
117
}
118
});
119
fmtln!(fmt, ")");
120
},
121
);
122
});
123
124
fmt.add_block(&format!("impl core::str::FromStr for {name}"), |fmt| {
125
fmtln!(fmt, "type Err = ();");
126
fmt.add_block("fn from_str(s: &str) -> Result<Self, Self::Err>", |fmt| {
127
fmt.add_block("match s", |fmt| {
128
for v in values.iter() {
129
fmtln!(fmt, "\"{}\" => Ok(Self::{}),", v, camel_case(v));
130
}
131
fmtln!(fmt, "_ => Err(()),");
132
});
133
});
134
});
135
}
136
137
/// Emit real enum for the Enum settings.
138
fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) {
139
for setting in group.settings.iter() {
140
let values = match setting.specific {
141
SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue,
142
SpecificSetting::Enum(ref values) => values,
143
};
144
let name = camel_case(setting.name);
145
146
fmt.doc_comment(format!("Values for `{}.{}`.", group.name, setting.name));
147
fmtln!(fmt, "#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]");
148
fmt.add_block(&format!("pub enum {name}"), |fmt| {
149
for v in values.iter() {
150
fmt.doc_comment(format!("`{v}`."));
151
fmtln!(fmt, "{},", camel_case(v));
152
}
153
});
154
155
fmt.add_block(&format!("impl {name}"), |fmt| {
156
gen_enum_all(&name, values, fmt);
157
});
158
159
gen_to_and_from_str(&name, values, fmt);
160
}
161
}
162
163
/// Emit a getter function for `setting`.
164
fn gen_getter(setting: &Setting, fmt: &mut Formatter) {
165
fmt.doc_comment(format!("{}\n{}", setting.description, setting.comment));
166
match setting.specific {
167
SpecificSetting::Bool(BoolSetting {
168
predicate_number, ..
169
}) => {
170
fmt.add_block(&format!("pub fn {}(&self) -> bool", setting.name), |fmt| {
171
fmtln!(fmt, "self.numbered_predicate({})", predicate_number);
172
});
173
}
174
SpecificSetting::Enum(ref values) => {
175
let ty = camel_case(setting.name);
176
fmt.add_block(
177
&format!("pub fn {}(&self) -> {}", setting.name, ty),
178
|fmt| {
179
let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));
180
for (i, v) in values.iter().enumerate() {
181
m.arm_no_fields(format!("{i}"), format!("{}::{}", ty, camel_case(v)));
182
}
183
m.arm_no_fields("_", "panic!(\"Invalid enum value\")");
184
fmt.add_match(m);
185
},
186
);
187
}
188
SpecificSetting::Num(_) => {
189
fmt.add_block(&format!("pub fn {}(&self) -> u8", setting.name), |fmt| {
190
fmtln!(fmt, "self.bytes[{}]", setting.byte_offset);
191
});
192
}
193
}
194
}
195
196
fn gen_pred_getter(predicate: &Predicate, group: &SettingGroup, fmt: &mut Formatter) {
197
fmt.doc_comment(format!("Computed predicate `{}`.", predicate.render(group)));
198
fmt.add_block(
199
&format!("pub fn {}(&self) -> bool", predicate.name),
200
|fmt| {
201
fmtln!(fmt, "self.numbered_predicate({})", predicate.number);
202
},
203
);
204
}
205
206
/// Emits getters for each setting value.
207
fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {
208
fmt.doc_comment("User-defined settings.");
209
fmtln!(fmt, "#[allow(dead_code, reason = \"generated code\")]");
210
fmt.add_block("impl Flags", |fmt| {
211
if !group.settings.is_empty() {
212
fmt.doc_comment("Dynamic numbered predicate getter.");
213
fmt.add_block("fn numbered_predicate(&self, p: usize) -> bool", |fmt| {
214
fmtln!(
215
fmt,
216
"self.bytes[{} + p / 8] & (1 << (p % 8)) != 0",
217
group.bool_start_byte_offset
218
);
219
});
220
}
221
222
for setting in &group.settings {
223
gen_getter(setting, fmt);
224
}
225
for predicate in &group.predicates {
226
gen_pred_getter(predicate, group, fmt);
227
}
228
});
229
}
230
231
#[derive(Hash, PartialEq, Eq)]
232
enum SettingOrPreset<'a> {
233
Setting(&'a Setting),
234
Preset(&'a Preset),
235
}
236
237
impl<'a> SettingOrPreset<'a> {
238
fn name(&self) -> &str {
239
match *self {
240
SettingOrPreset::Setting(s) => s.name,
241
SettingOrPreset::Preset(p) => p.name,
242
}
243
}
244
}
245
246
/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.
247
fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {
248
let mut enum_table = UniqueSeqTable::new();
249
250
let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();
251
252
// Generate descriptors.
253
fmtln!(
254
fmt,
255
"static DESCRIPTORS: [detail::Descriptor; {}] = [",
256
group.settings.len() + group.presets.len()
257
);
258
fmt.indent(|fmt| {
259
for (idx, setting) in group.settings.iter().enumerate() {
260
fmt.add_block("detail::Descriptor", |fmt| {
261
fmtln!(fmt, "name: \"{}\",", setting.name);
262
fmtln!(fmt, "description: \"{}\",", setting.description);
263
fmtln!(fmt, "offset: {},", setting.byte_offset);
264
match setting.specific {
265
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
266
fmtln!(
267
fmt,
268
"detail: detail::Detail::Bool {{ bit: {} }},",
269
bit_offset
270
);
271
}
272
SpecificSetting::Enum(ref values) => {
273
let offset = enum_table.add(values);
274
fmtln!(
275
fmt,
276
"detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},",
277
values.len() - 1,
278
offset
279
);
280
}
281
SpecificSetting::Num(_) => {
282
fmtln!(fmt, "detail: detail::Detail::Num,");
283
}
284
}
285
286
descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx);
287
});
288
fmtln!(fmt, ",");
289
}
290
291
for (idx, preset) in group.presets.iter().enumerate() {
292
fmt.add_block("detail::Descriptor", |fmt| {
293
fmtln!(fmt, "name: \"{}\",", preset.name);
294
fmtln!(fmt, "description: \"{}\",", preset.description);
295
fmtln!(fmt, "offset: {},", (idx as u8) * group.settings_size);
296
fmtln!(fmt, "detail: detail::Detail::Preset,");
297
});
298
fmtln!(fmt, ",");
299
300
let whole_idx = idx + group.settings.len();
301
descriptor_index_map.insert(SettingOrPreset::Preset(preset), whole_idx);
302
}
303
});
304
fmtln!(fmt, "];");
305
306
// Generate enumerators.
307
fmtln!(fmt, "static ENUMERATORS: [&str; {}] = [", enum_table.len());
308
fmt.indent(|fmt| {
309
for enum_val in enum_table.iter() {
310
fmtln!(fmt, "\"{}\",", enum_val);
311
}
312
});
313
fmtln!(fmt, "];");
314
315
// Generate hash table.
316
let mut hash_entries: Vec<SettingOrPreset> = Vec::new();
317
hash_entries.extend(group.settings.iter().map(SettingOrPreset::Setting));
318
hash_entries.extend(group.presets.iter().map(SettingOrPreset::Preset));
319
320
let hash_table = generate_table(hash_entries.iter(), hash_entries.len(), |entry| {
321
simple_hash(entry.name())
322
});
323
fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len());
324
fmt.indent(|fmt| {
325
for h in &hash_table {
326
match *h {
327
Some(setting_or_preset) => fmtln!(
328
fmt,
329
"{},",
330
&descriptor_index_map
331
.get(setting_or_preset)
332
.unwrap()
333
.to_string()
334
),
335
None => fmtln!(fmt, "0xffff,"),
336
}
337
}
338
});
339
fmtln!(fmt, "];");
340
341
// Generate presets.
342
fmtln!(
343
fmt,
344
"static PRESETS: [(u8, u8); {}] = [",
345
group.presets.len() * (group.settings_size as usize)
346
);
347
fmt.indent(|fmt| {
348
for preset in &group.presets {
349
fmt.comment(format!(
350
"{}: {}",
351
preset.name,
352
preset.setting_names(group).collect::<Vec<_>>().join(", ")
353
));
354
for (mask, value) in preset.layout(group) {
355
fmtln!(fmt, "(0b{:08b}, 0b{:08b}),", mask, value);
356
}
357
}
358
});
359
fmtln!(fmt, "];");
360
}
361
362
fn gen_template(group: &SettingGroup, fmt: &mut Formatter) {
363
let mut default_bytes: Vec<u8> = vec![0; group.settings_size as usize];
364
for setting in &group.settings {
365
*default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte();
366
}
367
368
let default_bytes: Vec<String> = default_bytes.iter().map(|x| format!("{x:#04x}")).collect();
369
let default_bytes_str = default_bytes.join(", ");
370
371
fmt.add_block(
372
"static TEMPLATE: detail::Template = detail::Template",
373
|fmt| {
374
fmtln!(fmt, "name: \"{}\",", group.name);
375
fmtln!(fmt, "descriptors: &DESCRIPTORS,");
376
fmtln!(fmt, "enumerators: &ENUMERATORS,");
377
fmtln!(fmt, "hash_table: &HASH_TABLE,");
378
fmtln!(fmt, "defaults: &[{}],", default_bytes_str);
379
fmtln!(fmt, "presets: &PRESETS,");
380
},
381
);
382
fmtln!(fmt, ";");
383
384
fmt.doc_comment(format!(
385
"Create a `settings::Builder` for the {} settings group.",
386
group.name
387
));
388
fmt.add_block("pub fn builder() -> Builder", |fmt| {
389
fmtln!(fmt, "Builder::new(&TEMPLATE)");
390
});
391
}
392
393
fn gen_display(group: &SettingGroup, fmt: &mut Formatter) {
394
fmt.add_block("impl fmt::Display for Flags", |fmt| {
395
fmt.add_block(
396
"fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",
397
|fmt| {
398
fmtln!(fmt, "writeln!(f, \"[{}]\")?;", group.name);
399
fmt.add_block("for d in &DESCRIPTORS", |fmt| {
400
fmt.add_block("if !d.detail.is_preset()", |fmt| {
401
fmtln!(fmt, "write!(f, \"{{}} = \", d.name)?;");
402
fmtln!(
403
fmt,
404
"TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;",
405
);
406
fmtln!(fmt, "writeln!(f)?;");
407
});
408
});
409
fmtln!(fmt, "Ok(())");
410
},
411
);
412
});
413
}
414
415
fn gen_hash_key(fmt: &mut Formatter) {
416
fmt.add_block("impl Flags", |fmt| {
417
fmt.doc_comment("Get the flag values as raw bytes for hashing.");
418
fmt.add_block("pub fn hash_key(&self) -> &[u8]", |fmt| {
419
fmtln!(fmt, "&self.bytes");
420
});
421
});
422
}
423
424
fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
425
// Generate struct.
426
fmtln!(fmt, "#[derive(Clone, PartialEq, Hash)]");
427
fmt.doc_comment(format!("Flags group `{}`.", group.name));
428
fmt.add_block("pub struct Flags", |fmt| {
429
fmtln!(fmt, "bytes: [u8; {}],", group.byte_size());
430
});
431
432
gen_constructor(group, parent, fmt);
433
gen_iterator(group, fmt);
434
gen_enum_types(group, fmt);
435
gen_getters(group, fmt);
436
gen_descriptors(group, fmt);
437
gen_template(group, fmt);
438
gen_display(group, fmt);
439
gen_hash_key(fmt);
440
}
441
442
pub(crate) fn generate(
443
settings: &SettingGroup,
444
parent_group: ParentGroup,
445
filename: &str,
446
out_dir: &std::path::Path,
447
) -> Result<(), error::Error> {
448
let mut fmt = Formatter::new(Language::Rust);
449
gen_group(settings, parent_group, &mut fmt);
450
fmt.write(filename, out_dir)?;
451
Ok(())
452
}
453
454