cranelift_codegen_meta/
gen_settings.rs

1//! Generate the ISA-specific settings.
2
3use crate::cdsl::camel_case;
4use crate::cdsl::settings::{
5    BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,
6};
7use crate::constant_hash::generate_table;
8use crate::unique_table::UniqueSeqTable;
9use cranelift_codegen_shared::constant_hash::simple_hash;
10use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};
11use std::collections::HashMap;
12
13pub(crate) enum ParentGroup {
14    None,
15    Shared,
16}
17
18/// Emits the constructor of the Flags structure.
19fn 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.
70fn 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
91fn 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.
109fn 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.
138fn 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`.
164fn 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
196fn 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.
207fn 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)]
232enum SettingOrPreset<'a> {
233    Setting(&'a Setting),
234    Preset(&'a Preset),
235}
236
237impl<'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.
247fn 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
362fn 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
393fn 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
415fn 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
424fn 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
442pub(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}