1 //! Generate the ISA-specific settings. 2 3 use crate::cdsl::camel_case; 4 use crate::cdsl::settings::{ 5 BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting, 6 }; 7 use crate::constant_hash::generate_table; 8 use crate::unique_table::UniqueSeqTable; 9 use cranelift_codegen_shared::constant_hash::simple_hash; 10 use cranelift_srcgen::{Formatter, Language, Match, error, fmtln}; 11 use std::collections::HashMap; 12 13 pub(crate) enum ParentGroup { 14 None, 15 Shared, 16 } 17 18 /// Emits the constructor of the Flags structure. 19 fn 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. 67 fn 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 88 fn 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. 106 fn 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. 135 fn 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`. 161 fn 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 193 fn 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. 204 fn 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)] 241 enum SettingOrPreset<'a> { 242 Setting(&'a Setting), 243 Preset(&'a Preset), 244 } 245 246 impl<'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. 256 fn 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 371 fn 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 402 fn 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 424 fn 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 441 pub(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 } 452