moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
This commit is contained in:
387
cranelift/codegen/meta/src/cdsl/settings.rs
Normal file
387
cranelift/codegen/meta/src/cdsl/settings.rs
Normal file
@@ -0,0 +1,387 @@
|
||||
use std::iter;
|
||||
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct BoolSettingIndex(usize);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub struct BoolSetting {
|
||||
pub default: bool,
|
||||
pub bit_offset: u8,
|
||||
pub predicate_number: u8,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub enum SpecificSetting {
|
||||
Bool(BoolSetting),
|
||||
Enum(Vec<&'static str>),
|
||||
Num(u8),
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub 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 struct PresetIndex(usize);
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
pub 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 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 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.");
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the basic information needed to track the specific parts of a setting when building
|
||||
/// them.
|
||||
pub enum ProtoSpecificSetting {
|
||||
Bool(bool, u8),
|
||||
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 enum PredicateNode {
|
||||
OwnedBool(BoolSettingIndex),
|
||||
SharedBool(&'static str, &'static str),
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Predicate {
|
||||
pub name: &'static str,
|
||||
node: PredicateNode,
|
||||
pub number: u8,
|
||||
}
|
||||
|
||||
impl Predicate {
|
||||
pub fn render(&self, group: &SettingGroup) -> String {
|
||||
self.node.render(group)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SettingGroupBuilder {
|
||||
name: &'static str,
|
||||
settings: Vec<ProtoSetting>,
|
||||
presets: Vec<Preset>,
|
||||
predicates: Vec<Predicate>,
|
||||
predicate_number: u8,
|
||||
}
|
||||
|
||||
impl SettingGroupBuilder {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
settings: Vec::new(),
|
||||
presets: Vec::new(),
|
||||
predicates: Vec::new(),
|
||||
predicate_number: 0,
|
||||
}
|
||||
}
|
||||
|
||||
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.len() == 0,
|
||||
"predicates must be added after the boolean settings"
|
||||
);
|
||||
let predicate_number = self.predicate_number;
|
||||
self.predicate_number += 1;
|
||||
self.add_setting(
|
||||
name,
|
||||
comment,
|
||||
ProtoSpecificSetting::Bool(default, predicate_number),
|
||||
);
|
||||
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) {
|
||||
let number = self.predicate_number;
|
||||
self.predicate_number += 1;
|
||||
self.predicates.push(Predicate { name, node, number });
|
||||
}
|
||||
|
||||
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 anonymous predicates and 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.
|
||||
///
|
||||
/// After calling this method, no more settings can be added, but
|
||||
/// additional predicates can be made accessible with `number_predicate()`.
|
||||
pub fn finish(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;
|
||||
|
||||
// Then the boolean settings.
|
||||
for s in &self.settings {
|
||||
let (default, predicate_number) = match s.specific {
|
||||
ProtoSpecificSetting::Bool(default, predicate_number) => {
|
||||
(default, predicate_number)
|
||||
}
|
||||
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,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
assert!(
|
||||
group.predicates.len() == 0,
|
||||
"settings_size is the byte size before adding predicates"
|
||||
);
|
||||
group.settings_size = group.byte_size();
|
||||
|
||||
group.predicates.extend(self.predicates);
|
||||
group.presets.extend(self.presets);
|
||||
|
||||
group
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user