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