Path: blob/main/cranelift/codegen/meta/src/gen_settings.rs
3067 views
//! Generate the ISA-specific settings.12use crate::cdsl::camel_case;3use crate::cdsl::settings::{BoolSetting, Preset, Setting, SettingGroup, SpecificSetting};4use crate::constant_hash::generate_table;5use crate::unique_table::UniqueSeqTable;6use cranelift_codegen_shared::constant_hash::simple_hash;7use cranelift_srcgen::{Formatter, Language, Match, error, fmtln};8use std::collections::HashMap;910pub(crate) enum ParentGroup {11None,12Shared,13}1415/// Emits the constructor of the Flags structure.16fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {17let args = match parent {18ParentGroup::None => "builder: Builder",19ParentGroup::Shared => "shared: &settings::Flags, builder: &Builder",20};21fmt.add_block("impl Flags", |fmt| {22fmt.doc_comment(format!("Create flags {} settings group.", group.name));23fmtln!(24fmt,25"#[allow(unused_variables, reason = \"generated code\")]"26);27fmt.add_block(&format!("pub fn new({args}) -> Self"), |fmt| {28fmtln!(fmt, "let bvec = builder.state_for(\"{}\");", group.name);29fmtln!(30fmt,31"let mut {} = Self {{ bytes: [0; {}] }};",32group.name,33group.byte_size()34);35fmtln!(36fmt,37"debug_assert_eq!(bvec.len(), {});",38group.settings_size39);40fmtln!(41fmt,42"{}.bytes[0..{}].copy_from_slice(&bvec);",43group.name,44group.settings_size45);4647fmtln!(fmt, "{}", group.name);48});49});50}5152/// Generates the `iter` function.53fn gen_iterator(group: &SettingGroup, fmt: &mut Formatter) {54fmt.add_block("impl Flags",|fmt| {55fmt.doc_comment("Iterates the setting values.");56fmt.add_block("pub fn iter(&self) -> impl Iterator<Item = Value> + use<>",|fmt| {57fmtln!(fmt, "let mut bytes = [0; {}];", group.settings_size);58fmtln!(fmt, "bytes.copy_from_slice(&self.bytes[0..{}]);", group.settings_size);59fmt.add_block("DESCRIPTORS.iter().filter_map(move |d|", |fmt| {60fmt.add_block("let values = match &d.detail", |fmt| {61fmtln!(fmt, "detail::Detail::Preset => return None,");62fmtln!(fmt, "detail::Detail::Enum {{ last, enumerators }} => Some(TEMPLATE.enums(*last, *enumerators)),");63fmtln!(fmt, "_ => None");64});65fmtln!(fmt, ";");66fmtln!(fmt, "Some(Value {{ name: d.name, detail: d.detail, values, value: bytes[d.offset as usize] }})");67});68fmtln!(fmt, ")");69});70});71}7273/// Generates a `all()` function with all options for this enum74fn gen_enum_all(name: &str, values: &[&'static str], fmt: &mut Formatter) {75fmtln!(76fmt,77"/// Returns a slice with all possible [{}] values.",78name79);80fmt.add_block(&format!("pub fn all() -> &'static [{name}]"), |fmt| {81fmtln!(fmt, "&[");82fmt.indent(|fmt| {83for v in values.iter() {84fmtln!(fmt, "Self::{},", camel_case(v));85}86});87fmtln!(fmt, "]");88});89}9091/// Emit Display and FromStr implementations for enum settings.92fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {93fmt.add_block(&format!("impl fmt::Display for {name}"), |fmt| {94fmt.add_block(95"fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",96|fmt| {97fmt.add_block("f.write_str(match *self", |fmt| {98for v in values.iter() {99fmtln!(fmt, "Self::{} => \"{}\",", camel_case(v), v);100}101});102fmtln!(fmt, ")");103},104);105});106107fmt.add_block(&format!("impl core::str::FromStr for {name}"), |fmt| {108fmtln!(fmt, "type Err = ();");109fmt.add_block("fn from_str(s: &str) -> Result<Self, Self::Err>", |fmt| {110fmt.add_block("match s", |fmt| {111for v in values.iter() {112fmtln!(fmt, "\"{}\" => Ok(Self::{}),", v, camel_case(v));113}114fmtln!(fmt, "_ => Err(()),");115});116});117});118}119120/// Emit real enum for the Enum settings.121fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) {122for setting in group.settings.iter() {123let values = match setting.specific {124SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue,125SpecificSetting::Enum(ref values) => values,126};127let name = camel_case(setting.name);128129fmt.doc_comment(format!("Values for `{}.{}`.", group.name, setting.name));130fmtln!(fmt, "#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]");131fmt.add_block(&format!("pub enum {name}"), |fmt| {132for v in values.iter() {133fmt.doc_comment(format!("`{v}`."));134fmtln!(fmt, "{},", camel_case(v));135}136});137138fmt.add_block(&format!("impl {name}"), |fmt| {139gen_enum_all(&name, values, fmt);140});141142gen_to_and_from_str(&name, values, fmt);143}144}145146/// Emit a getter function for `setting`.147fn gen_getter(setting: &Setting, fmt: &mut Formatter) {148fmt.doc_comment(format!("{}\n{}", setting.description, setting.comment));149match setting.specific {150SpecificSetting::Bool(BoolSetting {151predicate_number, ..152}) => {153fmt.add_block(&format!("pub fn {}(&self) -> bool", setting.name), |fmt| {154fmtln!(fmt, "self.numbered_predicate({})", predicate_number);155});156}157SpecificSetting::Enum(ref values) => {158let ty = camel_case(setting.name);159fmt.add_block(160&format!("pub fn {}(&self) -> {}", setting.name, ty),161|fmt| {162let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));163for (i, v) in values.iter().enumerate() {164m.arm_no_fields(format!("{i}"), format!("{}::{}", ty, camel_case(v)));165}166m.arm_no_fields("_", "panic!(\"Invalid enum value\")");167fmt.add_match(m);168},169);170}171SpecificSetting::Num(_) => {172fmt.add_block(&format!("pub fn {}(&self) -> u8", setting.name), |fmt| {173fmtln!(fmt, "self.bytes[{}]", setting.byte_offset);174});175}176}177}178179/// Emits getters for each setting value.180fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {181fmt.doc_comment("User-defined settings.");182fmtln!(fmt, "#[allow(dead_code, reason = \"generated code\")]");183fmt.add_block("impl Flags", |fmt| {184if !group.settings.is_empty() {185fmt.doc_comment("Dynamic numbered predicate getter.");186fmt.add_block("fn numbered_predicate(&self, p: usize) -> bool", |fmt| {187fmtln!(188fmt,189"self.bytes[{} + p / 8] & (1 << (p % 8)) != 0",190group.bool_start_byte_offset191);192});193}194195for setting in &group.settings {196gen_getter(setting, fmt);197}198});199}200201#[derive(Hash, PartialEq, Eq)]202enum SettingOrPreset<'a> {203Setting(&'a Setting),204Preset(&'a Preset),205}206207impl<'a> SettingOrPreset<'a> {208fn name(&self) -> &str {209match *self {210SettingOrPreset::Setting(s) => s.name,211SettingOrPreset::Preset(p) => p.name,212}213}214}215216/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.217fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {218let mut enum_table = UniqueSeqTable::new();219220let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();221222// Generate descriptors.223fmtln!(224fmt,225"static DESCRIPTORS: [detail::Descriptor; {}] = [",226group.settings.len() + group.presets.len()227);228fmt.indent(|fmt| {229for (idx, setting) in group.settings.iter().enumerate() {230fmt.add_block("detail::Descriptor", |fmt| {231fmtln!(fmt, "name: \"{}\",", setting.name);232fmtln!(fmt, "description: \"{}\",", setting.description);233fmtln!(fmt, "offset: {},", setting.byte_offset);234match setting.specific {235SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {236fmtln!(237fmt,238"detail: detail::Detail::Bool {{ bit: {} }},",239bit_offset240);241}242SpecificSetting::Enum(ref values) => {243let offset = enum_table.add(values);244fmtln!(245fmt,246"detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},",247values.len() - 1,248offset249);250}251SpecificSetting::Num(_) => {252fmtln!(fmt, "detail: detail::Detail::Num,");253}254}255256descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx);257});258fmtln!(fmt, ",");259}260261for (idx, preset) in group.presets.iter().enumerate() {262fmt.add_block("detail::Descriptor", |fmt| {263fmtln!(fmt, "name: \"{}\",", preset.name);264fmtln!(fmt, "description: \"{}\",", preset.description);265fmtln!(fmt, "offset: {},", (idx as u8) * group.settings_size);266fmtln!(fmt, "detail: detail::Detail::Preset,");267});268fmtln!(fmt, ",");269270let whole_idx = idx + group.settings.len();271descriptor_index_map.insert(SettingOrPreset::Preset(preset), whole_idx);272}273});274fmtln!(fmt, "];");275276// Generate enumerators.277fmtln!(fmt, "static ENUMERATORS: [&str; {}] = [", enum_table.len());278fmt.indent(|fmt| {279for enum_val in enum_table.iter() {280fmtln!(fmt, "\"{}\",", enum_val);281}282});283fmtln!(fmt, "];");284285// Generate hash table.286let mut hash_entries: Vec<SettingOrPreset> = Vec::new();287hash_entries.extend(group.settings.iter().map(SettingOrPreset::Setting));288hash_entries.extend(group.presets.iter().map(SettingOrPreset::Preset));289290let hash_table = generate_table(hash_entries.iter(), hash_entries.len(), |entry| {291simple_hash(entry.name())292});293fmtln!(fmt, "static HASH_TABLE: [u16; {}] = [", hash_table.len());294fmt.indent(|fmt| {295for h in &hash_table {296match *h {297Some(setting_or_preset) => fmtln!(298fmt,299"{},",300&descriptor_index_map301.get(setting_or_preset)302.unwrap()303.to_string()304),305None => fmtln!(fmt, "0xffff,"),306}307}308});309fmtln!(fmt, "];");310311// Generate presets.312fmtln!(313fmt,314"static PRESETS: [(u8, u8); {}] = [",315group.presets.len() * (group.settings_size as usize)316);317fmt.indent(|fmt| {318for preset in &group.presets {319fmt.comment(format!(320"{}: {}",321preset.name,322preset.setting_names(group).collect::<Vec<_>>().join(", ")323));324for (mask, value) in preset.layout(group) {325fmtln!(fmt, "(0b{:08b}, 0b{:08b}),", mask, value);326}327}328});329fmtln!(fmt, "];");330}331332fn gen_template(group: &SettingGroup, fmt: &mut Formatter) {333let mut default_bytes: Vec<u8> = vec![0; group.settings_size as usize];334for setting in &group.settings {335*default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte();336}337338let default_bytes: Vec<String> = default_bytes.iter().map(|x| format!("{x:#04x}")).collect();339let default_bytes_str = default_bytes.join(", ");340341fmt.add_block(342"static TEMPLATE: detail::Template = detail::Template",343|fmt| {344fmtln!(fmt, "name: \"{}\",", group.name);345fmtln!(fmt, "descriptors: &DESCRIPTORS,");346fmtln!(fmt, "enumerators: &ENUMERATORS,");347fmtln!(fmt, "hash_table: &HASH_TABLE,");348fmtln!(fmt, "defaults: &[{}],", default_bytes_str);349fmtln!(fmt, "presets: &PRESETS,");350},351);352fmtln!(fmt, ";");353354fmt.doc_comment(format!(355"Create a `settings::Builder` for the {} settings group.",356group.name357));358fmt.add_block("pub fn builder() -> Builder", |fmt| {359fmtln!(fmt, "Builder::new(&TEMPLATE)");360});361}362363fn gen_display(group: &SettingGroup, fmt: &mut Formatter) {364fmt.add_block("impl fmt::Display for Flags", |fmt| {365fmt.add_block(366"fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result",367|fmt| {368fmtln!(fmt, "writeln!(f, \"[{}]\")?;", group.name);369fmt.add_block("for d in &DESCRIPTORS", |fmt| {370fmt.add_block("if !d.detail.is_preset()", |fmt| {371fmtln!(fmt, "write!(f, \"{{}} = \", d.name)?;");372fmtln!(373fmt,374"TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;",375);376fmtln!(fmt, "writeln!(f)?;");377});378});379fmtln!(fmt, "Ok(())");380},381);382});383}384385fn gen_hash_key(fmt: &mut Formatter) {386fmt.add_block("impl Flags", |fmt| {387fmt.doc_comment("Get the flag values as raw bytes for hashing.");388fmt.add_block("pub fn hash_key(&self) -> &[u8]", |fmt| {389fmtln!(fmt, "&self.bytes");390});391});392}393394fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {395// Generate struct.396fmtln!(fmt, "#[derive(Clone, PartialEq, Hash)]");397fmt.doc_comment(format!("Flags group `{}`.", group.name));398fmt.add_block("pub struct Flags", |fmt| {399fmtln!(fmt, "bytes: [u8; {}],", group.byte_size());400});401402gen_constructor(group, parent, fmt);403gen_iterator(group, fmt);404gen_enum_types(group, fmt);405gen_getters(group, fmt);406gen_descriptors(group, fmt);407gen_template(group, fmt);408gen_display(group, fmt);409gen_hash_key(fmt);410}411412pub(crate) fn generate(413settings: &SettingGroup,414parent_group: ParentGroup,415filename: &str,416out_dir: &std::path::Path,417) -> Result<(), error::Error> {418let mut fmt = Formatter::new(Language::Rust);419gen_group(settings, parent_group, &mut fmt);420fmt.write(filename, out_dir)?;421Ok(())422}423424425