summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs')
-rw-r--r--third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs407
1 files changed, 407 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs b/third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs
new file mode 100644
index 0000000000..217bad9955
--- /dev/null
+++ b/third_party/rust/cranelift-codegen-meta/src/cdsl/settings.rs
@@ -0,0 +1,407 @@
+use std::iter;
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq)]
+pub(crate) struct BoolSettingIndex(usize);
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) struct BoolSetting {
+ pub default: bool,
+ pub bit_offset: u8,
+ pub predicate_number: u8,
+}
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) enum SpecificSetting {
+ Bool(BoolSetting),
+ Enum(Vec<&'static str>),
+ Num(u8),
+}
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) struct Setting {
+ pub name: &'static str,
+ pub comment: &'static str,
+ pub specific: SpecificSetting,
+ pub byte_offset: u8,
+}
+
+impl Setting {
+ pub fn default_byte(&self) -> u8 {
+ match self.specific {
+ SpecificSetting::Bool(BoolSetting {
+ default,
+ bit_offset,
+ ..
+ }) => {
+ if default {
+ 1 << bit_offset
+ } else {
+ 0
+ }
+ }
+ SpecificSetting::Enum(_) => 0,
+ SpecificSetting::Num(default) => default,
+ }
+ }
+
+ fn byte_for_value(&self, v: bool) -> u8 {
+ match self.specific {
+ SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
+ if v {
+ 1 << bit_offset
+ } else {
+ 0
+ }
+ }
+ _ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
+ }
+ }
+
+ fn byte_mask(&self) -> u8 {
+ match self.specific {
+ SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => 1 << bit_offset,
+ _ => panic!("byte_for_value shouldn't be used for non-boolean settings."),
+ }
+ }
+}
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) struct PresetIndex(usize);
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) enum PresetType {
+ BoolSetting(BoolSettingIndex),
+ OtherPreset(PresetIndex),
+}
+
+impl Into<PresetType> for BoolSettingIndex {
+ fn into(self) -> PresetType {
+ PresetType::BoolSetting(self)
+ }
+}
+impl Into<PresetType> for PresetIndex {
+ fn into(self) -> PresetType {
+ PresetType::OtherPreset(self)
+ }
+}
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) struct Preset {
+ pub name: &'static str,
+ values: Vec<BoolSettingIndex>,
+}
+
+impl Preset {
+ pub fn layout(&self, group: &SettingGroup) -> Vec<(u8, u8)> {
+ let mut layout: Vec<(u8, u8)> = iter::repeat((0, 0))
+ .take(group.settings_size as usize)
+ .collect();
+ for bool_index in &self.values {
+ let setting = &group.settings[bool_index.0];
+ let mask = setting.byte_mask();
+ let val = setting.byte_for_value(true);
+ assert!((val & !mask) == 0);
+ let (ref mut l_mask, ref mut l_val) =
+ *layout.get_mut(setting.byte_offset as usize).unwrap();
+ *l_mask |= mask;
+ *l_val = (*l_val & !mask) | val;
+ }
+ layout
+ }
+}
+
+pub(crate) struct SettingGroup {
+ pub name: &'static str,
+ pub settings: Vec<Setting>,
+ pub bool_start_byte_offset: u8,
+ pub settings_size: u8,
+ pub presets: Vec<Preset>,
+ pub predicates: Vec<Predicate>,
+}
+
+impl SettingGroup {
+ fn num_bool_settings(&self) -> u8 {
+ self.settings
+ .iter()
+ .filter(|s| {
+ if let SpecificSetting::Bool(_) = s.specific {
+ true
+ } else {
+ false
+ }
+ })
+ .count() as u8
+ }
+
+ pub fn byte_size(&self) -> u8 {
+ let num_predicates = self.num_bool_settings() + (self.predicates.len() as u8);
+ self.bool_start_byte_offset + (num_predicates + 7) / 8
+ }
+
+ pub fn get_bool(&self, name: &'static str) -> (BoolSettingIndex, &Self) {
+ for (i, s) in self.settings.iter().enumerate() {
+ if let SpecificSetting::Bool(_) = s.specific {
+ if s.name == name {
+ return (BoolSettingIndex(i), self);
+ }
+ }
+ }
+ panic!("Should have found bool setting by name.");
+ }
+
+ pub fn predicate_by_name(&self, name: &'static str) -> SettingPredicateNumber {
+ self.predicates
+ .iter()
+ .find(|pred| pred.name == name)
+ .unwrap_or_else(|| panic!("unknown predicate {}", name))
+ .number
+ }
+}
+
+/// This is the basic information needed to track the specific parts of a setting when building
+/// them.
+pub(crate) enum ProtoSpecificSetting {
+ Bool(bool),
+ Enum(Vec<&'static str>),
+ Num(u8),
+}
+
+/// This is the information provided during building for a setting.
+struct ProtoSetting {
+ name: &'static str,
+ comment: &'static str,
+ specific: ProtoSpecificSetting,
+}
+
+#[derive(Hash, PartialEq, Eq)]
+pub(crate) enum PredicateNode {
+ OwnedBool(BoolSettingIndex),
+ SharedBool(&'static str, &'static str),
+ Not(Box<PredicateNode>),
+ And(Box<PredicateNode>, Box<PredicateNode>),
+}
+
+impl Into<PredicateNode> for BoolSettingIndex {
+ fn into(self) -> PredicateNode {
+ PredicateNode::OwnedBool(self)
+ }
+}
+impl<'a> Into<PredicateNode> for (BoolSettingIndex, &'a SettingGroup) {
+ fn into(self) -> PredicateNode {
+ let (index, group) = (self.0, self.1);
+ let setting = &group.settings[index.0];
+ PredicateNode::SharedBool(group.name, setting.name)
+ }
+}
+
+impl PredicateNode {
+ fn render(&self, group: &SettingGroup) -> String {
+ match *self {
+ PredicateNode::OwnedBool(bool_setting_index) => format!(
+ "{}.{}()",
+ group.name, group.settings[bool_setting_index.0].name
+ ),
+ PredicateNode::SharedBool(ref group_name, ref bool_name) => {
+ format!("{}.{}()", group_name, bool_name)
+ }
+ PredicateNode::And(ref lhs, ref rhs) => {
+ format!("{} && {}", lhs.render(group), rhs.render(group))
+ }
+ PredicateNode::Not(ref node) => format!("!({})", node.render(group)),
+ }
+ }
+}
+
+struct ProtoPredicate {
+ pub name: &'static str,
+ node: PredicateNode,
+}
+
+pub(crate) type SettingPredicateNumber = u8;
+
+pub(crate) struct Predicate {
+ pub name: &'static str,
+ node: PredicateNode,
+ pub number: SettingPredicateNumber,
+}
+
+impl Predicate {
+ pub fn render(&self, group: &SettingGroup) -> String {
+ self.node.render(group)
+ }
+}
+
+pub(crate) struct SettingGroupBuilder {
+ name: &'static str,
+ settings: Vec<ProtoSetting>,
+ presets: Vec<Preset>,
+ predicates: Vec<ProtoPredicate>,
+}
+
+impl SettingGroupBuilder {
+ pub fn new(name: &'static str) -> Self {
+ Self {
+ name,
+ settings: Vec::new(),
+ presets: Vec::new(),
+ predicates: Vec::new(),
+ }
+ }
+
+ fn add_setting(
+ &mut self,
+ name: &'static str,
+ comment: &'static str,
+ specific: ProtoSpecificSetting,
+ ) {
+ self.settings.push(ProtoSetting {
+ name,
+ comment,
+ specific,
+ })
+ }
+
+ pub fn add_bool(
+ &mut self,
+ name: &'static str,
+ comment: &'static str,
+ default: bool,
+ ) -> BoolSettingIndex {
+ assert!(
+ self.predicates.is_empty(),
+ "predicates must be added after the boolean settings"
+ );
+ self.add_setting(name, comment, ProtoSpecificSetting::Bool(default));
+ BoolSettingIndex(self.settings.len() - 1)
+ }
+
+ pub fn add_enum(
+ &mut self,
+ name: &'static str,
+ comment: &'static str,
+ values: Vec<&'static str>,
+ ) {
+ self.add_setting(name, comment, ProtoSpecificSetting::Enum(values));
+ }
+
+ pub fn add_num(&mut self, name: &'static str, comment: &'static str, default: u8) {
+ self.add_setting(name, comment, ProtoSpecificSetting::Num(default));
+ }
+
+ pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) {
+ self.predicates.push(ProtoPredicate { name, node });
+ }
+
+ pub fn add_preset(&mut self, name: &'static str, args: Vec<PresetType>) -> PresetIndex {
+ let mut values = Vec::new();
+ for arg in args {
+ match arg {
+ PresetType::OtherPreset(index) => {
+ values.extend(self.presets[index.0].values.iter());
+ }
+ PresetType::BoolSetting(index) => values.push(index),
+ }
+ }
+ self.presets.push(Preset { name, values });
+ PresetIndex(self.presets.len() - 1)
+ }
+
+ /// Compute the layout of the byte vector used to represent this settings
+ /// group.
+ ///
+ /// The byte vector contains the following entries in order:
+ ///
+ /// 1. Byte-sized settings like `NumSetting` and `EnumSetting`.
+ /// 2. `BoolSetting` settings.
+ /// 3. Precomputed named predicates.
+ /// 4. Other numbered predicates, including parent predicates that need to be accessible by
+ /// number.
+ ///
+ /// Set `self.settings_size` to the length of the byte vector prefix that
+ /// contains the settings. All bytes after that are computed, not
+ /// configured.
+ ///
+ /// Set `self.boolean_offset` to the beginning of the numbered predicates,
+ /// 2. in the list above.
+ ///
+ /// Assign `byte_offset` and `bit_offset` fields in all settings.
+ pub fn build(self) -> SettingGroup {
+ let mut group = SettingGroup {
+ name: self.name,
+ settings: Vec::new(),
+ bool_start_byte_offset: 0,
+ settings_size: 0,
+ presets: Vec::new(),
+ predicates: Vec::new(),
+ };
+
+ let mut byte_offset = 0;
+
+ // Assign the non-boolean settings first.
+ for s in &self.settings {
+ let specific = match s.specific {
+ ProtoSpecificSetting::Bool(..) => continue,
+ ProtoSpecificSetting::Enum(ref values) => SpecificSetting::Enum(values.clone()),
+ ProtoSpecificSetting::Num(default) => SpecificSetting::Num(default),
+ };
+
+ group.settings.push(Setting {
+ name: s.name,
+ comment: s.comment,
+ byte_offset,
+ specific,
+ });
+
+ byte_offset += 1;
+ }
+
+ group.bool_start_byte_offset = byte_offset;
+
+ let mut predicate_number = 0;
+
+ // Then the boolean settings.
+ for s in &self.settings {
+ let default = match s.specific {
+ ProtoSpecificSetting::Bool(default) => default,
+ ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,
+ };
+ group.settings.push(Setting {
+ name: s.name,
+ comment: s.comment,
+ byte_offset: byte_offset + predicate_number / 8,
+ specific: SpecificSetting::Bool(BoolSetting {
+ default,
+ bit_offset: predicate_number % 8,
+ predicate_number,
+ }),
+ });
+ predicate_number += 1;
+ }
+
+ assert!(
+ group.predicates.is_empty(),
+ "settings_size is the byte size before adding predicates"
+ );
+ group.settings_size = group.byte_size();
+
+ // Sort predicates by name to ensure the same order as the Python code.
+ let mut predicates = self.predicates;
+ predicates.sort_by_key(|predicate| predicate.name);
+
+ group
+ .predicates
+ .extend(predicates.into_iter().map(|predicate| {
+ let number = predicate_number;
+ predicate_number += 1;
+ Predicate {
+ name: predicate.name,
+ node: predicate.node,
+ number,
+ }
+ }));
+
+ group.presets.extend(self.presets);
+
+ group
+ }
+}