cranelift_codegen_meta/
gen_settings.rs

1//! Generate the ISA-specific settings.
2
3use crate::cdsl::camel_case;
4use crate::cdsl::settings::{BoolSetting, Preset, Setting, SettingGroup, SpecificSetting};
5use crate::constant_hash::generate_table;
6use crate::unique_table::UniqueSeqTable;
7use cranelift_codegen_shared::constant_hash::simple_hash;
8use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};
9use std::collections::HashMap;
10
11pub(crate) enum ParentGroup {
12    None,
13    Shared,
14}
15
16/// Emits the constructor of the Flags structure.
17fn 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.
54fn 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
75fn 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.
93fn 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.
122fn 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`.
148fn 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.
181fn 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)]
203enum SettingOrPreset<'a> {
204    Setting(&'a Setting),
205    Preset(&'a Preset),
206}
207
208impl<'a> SettingOrPreset<'a> {
209    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.
218fn 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
333fn 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
364fn 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
386fn 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
395fn 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
413pub(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}