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.
gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter)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.
gen_iterator(group: &SettingGroup, fmt: &mut Formatter)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
gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter)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.
gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter)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.
gen_enum_types(group: &SettingGroup, fmt: &mut Formatter)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`.
gen_getter(setting: &Setting, fmt: &mut Formatter)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.
gen_getters(group: &SettingGroup, fmt: &mut Formatter)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> {
name(&self) -> &str209     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.
gen_descriptors(group: &SettingGroup, fmt: &mut Formatter)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 
gen_template(group: &SettingGroup, fmt: &mut Formatter)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 
gen_display(group: &SettingGroup, fmt: &mut Formatter)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 
gen_hash_key(fmt: &mut Formatter)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 
gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter)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 
generate( settings: &SettingGroup, parent_group: ParentGroup, filename: &str, out_dir: &std::path::Path, ) -> Result<(), error::Error>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