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