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::{error, fmtln, Formatter, Language, Match};
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!(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.
67fn 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
88fn 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.
106fn 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.
135fn 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`.
161fn 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
193fn 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.
204fn 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)]
241enum SettingOrPreset<'a> {
242    Setting(&'a Setting),
243    Preset(&'a Preset),
244}
245
246impl<'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.
256fn 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
371fn 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
402fn 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
424fn 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
441pub(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}