Path: blob/main/cranelift/codegen/meta/src/cdsl/settings.rs
1693 views
use std::iter;12#[derive(Clone, Copy, Hash, PartialEq, Eq)]3pub(crate) struct BoolSettingIndex(usize);45#[derive(Hash, PartialEq, Eq)]6pub(crate) struct BoolSetting {7pub default: bool,8pub bit_offset: u8,9pub predicate_number: u8,10}1112#[derive(Hash, PartialEq, Eq)]13pub(crate) enum SpecificSetting {14Bool(BoolSetting),15Enum(Vec<&'static str>),16Num(u8),17}1819#[derive(Hash, PartialEq, Eq)]20pub(crate) struct Setting {21pub name: &'static str,22pub description: &'static str,23pub comment: &'static str,24pub specific: SpecificSetting,25pub byte_offset: u8,26}2728impl Setting {29pub fn default_byte(&self) -> u8 {30match self.specific {31SpecificSetting::Bool(BoolSetting {32default,33bit_offset,34..35}) => {36if default {371 << bit_offset38} else {39040}41}42SpecificSetting::Enum(_) => 0,43SpecificSetting::Num(default) => default,44}45}4647fn byte_for_value(&self, v: bool) -> u8 {48match self.specific {49SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {50if v {511 << bit_offset52} else {53054}55}56_ => panic!("byte_for_value shouldn't be used for non-boolean settings."),57}58}5960fn byte_mask(&self) -> u8 {61match self.specific {62SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset,63_ => panic!("byte_for_value shouldn't be used for non-boolean settings."),64}65}66}6768#[derive(Hash, PartialEq, Eq, Copy, Clone)]69pub(crate) struct PresetIndex(usize);7071#[derive(Hash, PartialEq, Eq)]72pub(crate) enum PresetType {73BoolSetting(BoolSettingIndex),74OtherPreset(PresetIndex),75}7677impl From<BoolSettingIndex> for PresetType {78fn from(bool_setting_index: BoolSettingIndex) -> Self {79PresetType::BoolSetting(bool_setting_index)80}81}82impl From<PresetIndex> for PresetType {83fn from(value: PresetIndex) -> Self {84PresetType::OtherPreset(value)85}86}8788#[derive(Hash, PartialEq, Eq)]89pub(crate) struct Preset {90pub name: &'static str,91pub description: &'static str,92values: Vec<BoolSettingIndex>,93}9495impl Preset {96pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> {97let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0))98.take(group.settings_size as usize)99.collect();100for bool_index in &self.values {101let setting = &group.settings[bool_index.0];102let mask = setting.byte_mask();103let val = setting.byte_for_value(true);104assert!((val & !mask) == 0);105let (ref mut l_mask, ref mut l_val) =106*layout.get_mut(setting.byte_offset as usize).unwrap();107*l_mask |= mask;108*l_val = (*l_val & !mask) | val;109}110layout111}112113pub fn setting_names<'a>(114&'a self,115group: &'a SettingGroup,116) -> impl Iterator<Item = &'static str> + 'a {117self.values118.iter()119.map(|bool_index| group.settings[bool_index.0].name)120}121}122123pub(crate) struct SettingGroup {124pub name: &'static str,125pub settings: Vec<Setting>,126pub bool_start_byte_offset: u8,127pub settings_size: u8,128pub presets: Vec<Preset>,129pub predicates: Vec<Predicate>,130}131132impl SettingGroup {133fn num_bool_settings(&self) -> u8 {134self.settings135.iter()136.filter(|s| matches!(s.specific, SpecificSetting::Bool(_)))137.count() as u8138}139140pub fn byte_size(&self) -> u8 {141let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8);142self.bool_start_byte_offset + (num_predicates + 7) / 8143}144}145146/// This is the basic information needed to track the specific parts of a setting when building147/// them.148pub(crate) enum ProtoSpecificSetting {149Bool(bool),150Enum(Vec<&'static str>),151Num(u8),152}153154/// This is the information provided during building for a setting.155struct ProtoSetting {156name: &'static str,157description: &'static str,158comment: &'static str,159specific: ProtoSpecificSetting,160}161162#[derive(Hash, PartialEq, Eq)]163pub(crate) enum PredicateNode {164OwnedBool(BoolSettingIndex),165SharedBool(&'static str, &'static str),166And(Box<PredicateNode>, Box<PredicateNode>),167}168169impl From<BoolSettingIndex> for PredicateNode {170fn from(bool_setting_index: BoolSettingIndex) -> Self {171PredicateNode::OwnedBool(bool_setting_index)172}173}174175impl<'a> From<(BoolSettingIndex, &'a SettingGroup)> for PredicateNode {176fn from(val: (BoolSettingIndex, &'a SettingGroup)) -> Self {177let (index, group) = (val.0, val.1);178let setting = &group.settings[index.0];179PredicateNode::SharedBool(group.name, setting.name)180}181}182183impl PredicateNode {184fn render(&self, group: &SettingGroup) -> String {185match *self {186PredicateNode::OwnedBool(bool_setting_index) => format!(187"{}.{}()",188group.name, group.settings[bool_setting_index.0].name189),190PredicateNode::SharedBool(ref group_name, ref bool_name) => {191format!("{group_name}.{bool_name}()")192}193PredicateNode::And(ref lhs, ref rhs) => {194format!("{} && {}", lhs.render(group), rhs.render(group))195}196}197}198}199200struct ProtoPredicate {201pub name: &'static str,202node: PredicateNode,203}204205pub(crate) type SettingPredicateNumber = u8;206207pub(crate) struct Predicate {208pub name: &'static str,209node: PredicateNode,210pub number: SettingPredicateNumber,211}212213impl Predicate {214pub fn render(&self, group: &SettingGroup) -> String {215self.node.render(group)216}217}218219pub(crate) struct SettingGroupBuilder {220name: &'static str,221settings: Vec<ProtoSetting>,222presets: Vec<Preset>,223predicates: Vec<ProtoPredicate>,224}225226impl SettingGroupBuilder {227pub fn new(name: &'static str) -> Self {228Self {229name,230settings: Vec::new(),231presets: Vec::new(),232predicates: Vec::new(),233}234}235236fn add_setting(237&mut self,238name: &'static str,239description: &'static str,240comment: &'static str,241specific: ProtoSpecificSetting,242) {243self.settings.push(ProtoSetting {244name,245description,246comment,247specific,248})249}250251pub fn add_bool(252&mut self,253name: &'static str,254description: &'static str,255comment: &'static str,256default: bool,257) -> BoolSettingIndex {258assert!(259self.predicates.is_empty(),260"predicates must be added after the boolean settings"261);262self.add_setting(263name,264description,265comment,266ProtoSpecificSetting::Bool(default),267);268BoolSettingIndex(self.settings.len() - 1)269}270271pub fn add_enum(272&mut self,273name: &'static str,274description: &'static str,275comment: &'static str,276values: Vec<&'static str>,277) {278self.add_setting(279name,280description,281comment,282ProtoSpecificSetting::Enum(values),283);284}285286pub fn add_num(287&mut self,288name: &'static str,289description: &'static str,290comment: &'static str,291default: u8,292) {293self.add_setting(294name,295description,296comment,297ProtoSpecificSetting::Num(default),298);299}300301pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) {302self.predicates.push(ProtoPredicate { name, node });303}304305pub fn add_preset(306&mut self,307name: &'static str,308description: &'static str,309args: Vec<PresetType>,310) -> PresetIndex {311let mut values = Vec::new();312for arg in args {313match arg {314PresetType::OtherPreset(index) => {315values.extend(self.presets[index.0].values.iter());316}317PresetType::BoolSetting(index) => values.push(index),318}319}320self.presets.push(Preset {321name,322description,323values,324});325PresetIndex(self.presets.len() - 1)326}327328/// Compute the layout of the byte vector used to represent this settings329/// group.330///331/// The byte vector contains the following entries in order:332///333/// 1. Byte-sized settings like `NumSetting` and `EnumSetting`.334/// 2. `BoolSetting` settings.335/// 3. Precomputed named predicates.336/// 4. Other numbered predicates, including parent predicates that need to be accessible by337/// number.338///339/// Set `self.settings_size` to the length of the byte vector prefix that340/// contains the settings. All bytes after that are computed, not341/// configured.342///343/// Set `self.boolean_offset` to the beginning of the numbered predicates,344/// 2. in the list above.345///346/// Assign `byte_offset` and `bit_offset` fields in all settings.347pub fn build(self) -> SettingGroup {348let mut group = SettingGroup {349name: self.name,350settings: Vec::new(),351bool_start_byte_offset: 0,352settings_size: 0,353presets: Vec::new(),354predicates: Vec::new(),355};356357let mut byte_offset = 0;358359// Assign the non-boolean settings first.360for s in &self.settings {361let specific = match s.specific {362ProtoSpecificSetting::Bool(..) => continue,363ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()),364ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default),365};366367group.settings.push(Setting {368name: s.name,369description: s.description,370comment: s.comment,371byte_offset,372specific,373});374375byte_offset += 1;376}377378group.bool_start_byte_offset = byte_offset;379380let mut predicate_number = 0;381382// Then the boolean settings.383for s in &self.settings {384let default = match s.specific {385ProtoSpecificSetting::Bool(default) => default,386ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,387};388group.settings.push(Setting {389name: s.name,390description: s.description,391comment: s.comment,392byte_offset: byte_offset + predicate_number / 8,393specific: SpecificSetting::Bool(BoolSetting {394default,395bit_offset: predicate_number % 8,396predicate_number,397}),398});399predicate_number += 1;400}401402assert!(403group.predicates.is_empty(),404"settings_size is the byte size before adding predicates"405);406group.settings_size = group.byte_size();407408// Sort predicates by name to ensure the same order as the Python code.409let mut predicates = self.predicates;410predicates.sort_by_key(|predicate| predicate.name);411412group413.predicates414.extend(predicates.into_iter().map(|predicate| {415let number = predicate_number;416predicate_number += 1;417Predicate {418name: predicate.name,419node: predicate.node,420number,421}422}));423424group.presets.extend(self.presets);425426group427}428}429430431