Path: blob/main/cranelift/codegen/meta/src/gen_settings.rs
1692 views
//! Generate the ISA-specific settings.12use crate::cdsl::camel_case;3use crate::cdsl::settings::{4BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting,5};6use crate::constant_hash::generate_table;7use crate::unique_table::UniqueSeqTable;8use cranelift_codegen_shared::constant_hash::simple_hash;9use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};10use std::collections::HashMap;1112pub(crate) enum ParentGroup {13None,14Shared,15}1617/// Emits the constructor of the Flags structure.18fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {19let args = match parent {20ParentGroup::None => "builder: Builder",21ParentGroup::Shared => "shared: &settings::Flags, builder: &Builder",22};23fmt.add_block("impl Flags", |fmt| {24fmt.doc_comment(format!("Create flags {} settings group.", group.name));25fmtln!(26fmt,27"#[allow(unused_variables, reason = \"generated code\")]"28);29fmt.add_block(&format!("pub fn new({args}) -> Self"), |fmt| {30fmtln!(fmt, "let bvec = builder.state_for(\"{}\");", group.name);31fmtln!(32fmt,33"let mut {} = Self {{ bytes: [0; {}] }};",34group.name,35group.byte_size()36);37fmtln!(38fmt,39"debug_assert_eq!(bvec.len(), {});",40group.settings_size41);42fmtln!(43fmt,44"{}.bytes[0..{}].copy_from_slice(&bvec);",45group.name,46group.settings_size47);4849// Now compute the predicates.50for p in &group.predicates {51fmt.comment(format!("Precompute #{}.", p.number));52fmt.add_block(&format!("if {}", p.render(group)), |fmt| {53fmtln!(54fmt,55"{}.bytes[{}] |= 1 << {};",56group.name,57group.bool_start_byte_offset + p.number / 8,58p.number % 859);60});61}6263fmtln!(fmt, "{}", group.name);64});65});66}6768/// Generates the `iter` function.69fn gen_iterator(group: &SettingGroup, fmt: &mut Formatter) {70fmt.add_block("impl Flags",|fmt| {71fmt.doc_comment("Iterates the setting values.");72fmt.add_block("pub fn iter(&self) -> impl Iterator<Item = Value> + use<>",|fmt| {73fmtln!(fmt, "let mut bytes = [0; {}];", group.settings_size);74fmtln!(fmt, "bytes.copy_from_slice(&self.bytes[0..{}]);", group.settings_size);75fmt.add_block("DESCRIPTORS.iter().filter_map(move |d|", |fmt| {76fmt.add_block("let values = match &d.detail", |fmt| {77fmtln!(fmt, "detail::Detail::Preset => return None,");78fmtln!(fmt, "detail::Detail::Enum {{ last, enumerators }} => Some(TEMPLATE.enums(*last, *enumerators)),");79fmtln!(fmt, "_ => None");80});81fmtln!(fmt, ";");82fmtln!(fmt, "Some(Value {{ name: d.name, detail: d.detail, values, value: bytes[d.offset as usize] }})");83});84fmtln!(fmt, ")");85});86});87}8889/// Generates a `all()` function with all options for this enum90fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) {91fmtln!(92fmt,93"/// Returns a slice with all possible [{}] values.",94name95);96fmt.add_block(&format!("pub fn all() -> &'static [{name}]"), |fmt| {97fmtln!(fmt, "&[");98fmt.indent(|fmt| {99for v in values.iter() {100fmtln!(fmt, "Self::{},", camel_case(v));101}102});103fmtln!(fmt, "]");104});105}106107/// Emit Display and FromStr implementations for enum settings.108fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {109fmt.add_block(&format!("impl fmt::Display for {name}"), |fmt| {110fmt.add_block(111"fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",112|fmt| {113fmt.add_block("f.write_str(match *self", |fmt| {114for v in values.iter() {115fmtln!(fmt, "Self::{} => \"{}\",", camel_case(v), v);116}117});118fmtln!(fmt, ")");119},120);121});122123fmt.add_block(&format!("impl core::str::FromStr for {name}"), |fmt| {124fmtln!(fmt, "type Err = ();");125fmt.add_block("fn from_str(s: &str) -> Result<Self, Self::Err>", |fmt| {126fmt.add_block("match s", |fmt| {127for v in values.iter() {128fmtln!(fmt, "\"{}\" => Ok(Self::{}),", v, camel_case(v));129}130fmtln!(fmt, "_ => Err(()),");131});132});133});134}135136/// Emit real enum for the Enum settings.137fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) {138for setting in group.settings.iter() {139let values = match setting.specific {140SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue,141SpecificSetting::Enum(ref values) => values,142};143let name = camel_case(setting.name);144145fmt.doc_comment(format!("Values for `{}.{}`.", group.name, setting.name));146fmtln!(fmt, "#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]");147fmt.add_block(&format!("pub enum {name}"), |fmt| {148for v in values.iter() {149fmt.doc_comment(format!("`{v}`."));150fmtln!(fmt, "{},", camel_case(v));151}152});153154fmt.add_block(&format!("impl {name}"), |fmt| {155gen_enum_all(&name, values, fmt);156});157158gen_to_and_from_str(&name, values, fmt);159}160}161162/// Emit a getter function for `setting`.163fn gen_getter(setting: &Setting, fmt: &mut Formatter) {164fmt.doc_comment(format!("{}\n{}", setting.description, setting.comment));165match setting.specific {166SpecificSetting::Bool(BoolSetting {167predicate_number, ..168}) => {169fmt.add_block(&format!("pub fn {}(&self) -> bool", setting.name), |fmt| {170fmtln!(fmt, "self.numbered_predicate({})", predicate_number);171});172}173SpecificSetting::Enum(ref values) => {174let ty = camel_case(setting.name);175fmt.add_block(176&format!("pub fn {}(&self) -> {}", setting.name, ty),177|fmt| {178let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));179for (i, v) in values.iter().enumerate() {180m.arm_no_fields(format!("{i}"), format!("{}::{}", ty, camel_case(v)));181}182m.arm_no_fields("_", "panic!(\"Invalid enum value\")");183fmt.add_match(m);184},185);186}187SpecificSetting::Num(_) => {188fmt.add_block(&format!("pub fn {}(&self) -> u8", setting.name), |fmt| {189fmtln!(fmt, "self.bytes[{}]", setting.byte_offset);190});191}192}193}194195fn gen_pred_getter(predicate: &Predicate, group: &SettingGroup, fmt: &mut Formatter) {196fmt.doc_comment(format!("Computed predicate `{}`.", predicate.render(group)));197fmt.add_block(198&format!("pub fn {}(&self) -> bool", predicate.name),199|fmt| {200fmtln!(fmt, "self.numbered_predicate({})", predicate.number);201},202);203}204205/// Emits getters for each setting value.206fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {207fmt.doc_comment("User-defined settings.");208fmtln!(fmt, "#[allow(dead_code, reason = \"generated code\")]");209fmt.add_block("impl Flags", |fmt| {210if !group.settings.is_empty() {211fmt.doc_comment("Dynamic numbered predicate getter.");212fmt.add_block("fn numbered_predicate(&self, p: usize) -> bool", |fmt| {213fmtln!(214fmt,215"self.bytes[{} + p / 8] & (1 << (p % 8)) != 0",216group.bool_start_byte_offset217);218});219}220221for setting in &group.settings {222gen_getter(setting, fmt);223}224for predicate in &group.predicates {225gen_pred_getter(predicate, group, fmt);226}227});228}229230#[derive(Hash, PartialEq, Eq)]231enum SettingOrPreset<'a> {232Setting(&'a Setting),233Preset(&'a Preset),234}235236impl<'a> SettingOrPreset<'a> {237fn name(&self) -> &str {238match *self {239SettingOrPreset::Setting(s) => s.name,240SettingOrPreset::Preset(p) => p.name,241}242}243}244245/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.246fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {247let mut enum_table = UniqueSeqTable::new();248249let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();250251// Generate descriptors.252fmtln!(253fmt,254"static DESCRIPTORS: [detail::Descriptor; {}] = [",255group.settings.len() + group.presets.len()256);257fmt.indent(|fmt| {258for (idx, setting) in group.settings.iter().enumerate() {259fmt.add_block("detail::Descriptor", |fmt| {260fmtln!(fmt, "name: \"{}\",", setting.name);261fmtln!(fmt, "description: \"{}\",", setting.description);262fmtln!(fmt, "offset: {},", setting.byte_offset);263match setting.specific {264SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {265fmtln!(266fmt,267"detail: detail::Detail::Bool {{ bit: {} }},",268bit_offset269);270}271SpecificSetting::Enum(ref values) => {272let offset = enum_table.add(values);273fmtln!(274fmt,275"detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},",276values.len() - 1,277offset278);279}280SpecificSetting::Num(_) => {281fmtln!(fmt, "detail: detail::Detail::Num,");282}283}284285descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx);286});287fmtln!(fmt, ",");288}289290for (idx, preset) in group.presets.iter().enumerate() {291fmt.add_block("detail::Descriptor", |fmt| {292fmtln!(fmt, "name: \"{}\",", preset.name);293fmtln!(fmt, "description: \"{}\",", preset.description);294fmtln!(fmt, "offset: {},", (idx as u8) * group.settings_size);295fmtln!(fmt, "detail: detail::Detail::Preset,");296});297fmtln!(fmt, ",");298299let whole_idx = idx + group.settings.len();300descriptor_index_map.insert(SettingOrPreset::Preset(preset), whole_idx);301}302});303fmtln!(fmt, "];");304305// Generate enumerators.306fmtln!(fmt, "static ENUMERATORS: [&str; {}] = [", enum_table.len());307fmt.indent(|fmt| {308for enum_val in enum_table.iter() {309fmtln!(fmt, "\"{}\",", enum_val);310}311});312fmtln!(fmt, "];");313314// Generate hash table.315let mut hash_entries: Vec<SettingOrPreset> = Vec::new();316hash_entries.extend(group.settings.iter().map(SettingOrPreset::Setting));317hash_entries.extend(group.presets.iter().map(SettingOrPreset::Preset));318319let hash_table = generate_table(hash_entries.iter(), hash_entries.len(), |entry| {320simple_hash(entry.name())321});322fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len());323fmt.indent(|fmt| {324for h in &hash_table {325match *h {326Some(setting_or_preset) => fmtln!(327fmt,328"{},",329&descriptor_index_map330.get(setting_or_preset)331.unwrap()332.to_string()333),334None => fmtln!(fmt, "0xffff,"),335}336}337});338fmtln!(fmt, "];");339340// Generate presets.341fmtln!(342fmt,343"static PRESETS: [(u8, u8); {}] = [",344group.presets.len() * (group.settings_size as usize)345);346fmt.indent(|fmt| {347for preset in &group.presets {348fmt.comment(format!(349"{}: {}",350preset.name,351preset.setting_names(group).collect::<Vec<_>>().join(", ")352));353for (mask, value) in preset.layout(group) {354fmtln!(fmt, "(0b{:08b}, 0b{:08b}),", mask, value);355}356}357});358fmtln!(fmt, "];");359}360361fn gen_template(group: &SettingGroup, fmt: &mut Formatter) {362let mut default_bytes: Vec<u8> = vec![0; group.settings_size as usize];363for setting in &group.settings {364*default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte();365}366367let default_bytes: Vec<String> = default_bytes.iter().map(|x| format!("{x:#04x}")).collect();368let default_bytes_str = default_bytes.join(", ");369370fmt.add_block(371"static TEMPLATE: detail::Template = detail::Template",372|fmt| {373fmtln!(fmt, "name: \"{}\",", group.name);374fmtln!(fmt, "descriptors: &DESCRIPTORS,");375fmtln!(fmt, "enumerators: &ENUMERATORS,");376fmtln!(fmt, "hash_table: &HASH_TABLE,");377fmtln!(fmt, "defaults: &[{}],", default_bytes_str);378fmtln!(fmt, "presets: &PRESETS,");379},380);381fmtln!(fmt, ";");382383fmt.doc_comment(format!(384"Create a `settings::Builder` for the {} settings group.",385group.name386));387fmt.add_block("pub fn builder() -> Builder", |fmt| {388fmtln!(fmt, "Builder::new(&TEMPLATE)");389});390}391392fn gen_display(group: &SettingGroup, fmt: &mut Formatter) {393fmt.add_block("impl fmt::Display for Flags", |fmt| {394fmt.add_block(395"fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",396|fmt| {397fmtln!(fmt, "writeln!(f, \"[{}]\")?;", group.name);398fmt.add_block("for d in &DESCRIPTORS", |fmt| {399fmt.add_block("if !d.detail.is_preset()", |fmt| {400fmtln!(fmt, "write!(f, \"{{}} = \", d.name)?;");401fmtln!(402fmt,403"TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;",404);405fmtln!(fmt, "writeln!(f)?;");406});407});408fmtln!(fmt, "Ok(())");409},410);411});412}413414fn gen_hash_key(fmt: &mut Formatter) {415fmt.add_block("impl Flags", |fmt| {416fmt.doc_comment("Get the flag values as raw bytes for hashing.");417fmt.add_block("pub fn hash_key(&self) -> &[u8]", |fmt| {418fmtln!(fmt, "&self.bytes");419});420});421}422423fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {424// Generate struct.425fmtln!(fmt, "#[derive(Clone, PartialEq, Hash)]");426fmt.doc_comment(format!("Flags group `{}`.", group.name));427fmt.add_block("pub struct Flags", |fmt| {428fmtln!(fmt, "bytes: [u8; {}],", group.byte_size());429});430431gen_constructor(group, parent, fmt);432gen_iterator(group, fmt);433gen_enum_types(group, fmt);434gen_getters(group, fmt);435gen_descriptors(group, fmt);436gen_template(group, fmt);437gen_display(group, fmt);438gen_hash_key(fmt);439}440441pub(crate) fn generate(442settings: &SettingGroup,443parent_group: ParentGroup,444filename: &str,445out_dir: &std::path::Path,446) -> Result<(), error::Error> {447let mut fmt = Formatter::new(Language::Rust);448gen_group(settings, parent_group, &mut fmt);449fmt.write(filename, out_dir)?;450Ok(())451}452453454