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