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