cranelift_codegen_meta/
gen_settings.rs

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