[meta] Use named predicates for x86 settings in the Rust crate too;

And generate them using the same deterministic order that the Python
code uses.
This commit is contained in:
Benjamin Bouvier
2019-04-16 15:24:28 +02:00
parent 6a25354520
commit 390cfb37da
3 changed files with 62 additions and 25 deletions

View File

@@ -23,6 +23,15 @@ macro_rules! predicate {
($a:ident && $($b:tt)*) => { ($a:ident && $($b:tt)*) => {
PredicateNode::And(Box::new($a.into()), Box::new(predicate!($($b)*))) PredicateNode::And(Box::new($a.into()), Box::new(predicate!($($b)*)))
}; };
(!$a:ident && $($b:tt)*) => {
PredicateNode::And(
Box::new(PredicateNode::Not(Box::new($a.into()))),
Box::new(predicate!($($b)*))
)
};
(!$a:ident) => {
PredicateNode::Not(Box::new($a.into()))
};
($a:ident) => { ($a:ident) => {
$a.into() $a.into()
}; };

View File

@@ -153,7 +153,7 @@ impl SettingGroup {
/// This is the basic information needed to track the specific parts of a setting when building /// This is the basic information needed to track the specific parts of a setting when building
/// them. /// them.
pub enum ProtoSpecificSetting { pub enum ProtoSpecificSetting {
Bool(bool, u8), Bool(bool),
Enum(Vec<&'static str>), Enum(Vec<&'static str>),
Num(u8), Num(u8),
} }
@@ -169,6 +169,7 @@ struct ProtoSetting {
pub enum PredicateNode { pub enum PredicateNode {
OwnedBool(BoolSettingIndex), OwnedBool(BoolSettingIndex),
SharedBool(&'static str, &'static str), SharedBool(&'static str, &'static str),
Not(Box<PredicateNode>),
And(Box<PredicateNode>, Box<PredicateNode>), And(Box<PredicateNode>, Box<PredicateNode>),
} }
@@ -198,10 +199,16 @@ impl PredicateNode {
PredicateNode::And(ref lhs, ref rhs) => { PredicateNode::And(ref lhs, ref rhs) => {
format!("{} && {}", lhs.render(group), rhs.render(group)) format!("{} && {}", lhs.render(group), rhs.render(group))
} }
PredicateNode::Not(ref node) => format!("!({})", node.render(group)),
} }
} }
} }
struct ProtoPredicate {
pub name: &'static str,
node: PredicateNode,
}
pub struct Predicate { pub struct Predicate {
pub name: &'static str, pub name: &'static str,
node: PredicateNode, node: PredicateNode,
@@ -218,8 +225,7 @@ pub struct SettingGroupBuilder {
name: &'static str, name: &'static str,
settings: Vec<ProtoSetting>, settings: Vec<ProtoSetting>,
presets: Vec<Preset>, presets: Vec<Preset>,
predicates: Vec<Predicate>, predicates: Vec<ProtoPredicate>,
predicate_number: u8,
} }
impl SettingGroupBuilder { impl SettingGroupBuilder {
@@ -229,7 +235,6 @@ impl SettingGroupBuilder {
settings: Vec::new(), settings: Vec::new(),
presets: Vec::new(), presets: Vec::new(),
predicates: Vec::new(), predicates: Vec::new(),
predicate_number: 0,
} }
} }
@@ -256,13 +261,7 @@ impl SettingGroupBuilder {
self.predicates.len() == 0, self.predicates.len() == 0,
"predicates must be added after the boolean settings" "predicates must be added after the boolean settings"
); );
let predicate_number = self.predicate_number; self.add_setting(name, comment, ProtoSpecificSetting::Bool(default));
self.predicate_number += 1;
self.add_setting(
name,
comment,
ProtoSpecificSetting::Bool(default, predicate_number),
);
BoolSettingIndex(self.settings.len() - 1) BoolSettingIndex(self.settings.len() - 1)
} }
@@ -280,9 +279,7 @@ impl SettingGroupBuilder {
} }
pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) { pub fn add_predicate(&mut self, name: &'static str, node: PredicateNode) {
let number = self.predicate_number; self.predicates.push(ProtoPredicate { name, node });
self.predicate_number += 1;
self.predicates.push(Predicate { name, node, number });
} }
pub fn add_preset(&mut self, name: &'static str, args: Vec<PresetType>) -> PresetIndex { pub fn add_preset(&mut self, name: &'static str, args: Vec<PresetType>) -> PresetIndex {
@@ -307,8 +304,8 @@ impl SettingGroupBuilder {
/// 1. Byte-sized settings like `NumSetting` and `EnumSetting`. /// 1. Byte-sized settings like `NumSetting` and `EnumSetting`.
/// 2. `BoolSetting` settings. /// 2. `BoolSetting` settings.
/// 3. Precomputed named predicates. /// 3. Precomputed named predicates.
/// 4. Other numbered predicates, including anonymous predicates and parent /// 4. Other numbered predicates, including parent predicates that need to be accessible by
/// predicates that need to be accessible by number. /// number.
/// ///
/// Set `self.settings_size` to the length of the byte vector prefix that /// Set `self.settings_size` to the length of the byte vector prefix that
/// contains the settings. All bytes after that are computed, not /// contains the settings. All bytes after that are computed, not
@@ -318,9 +315,6 @@ impl SettingGroupBuilder {
/// 2. in the list above. /// 2. in the list above.
/// ///
/// Assign `byte_offset` and `bit_offset` fields in all settings. /// 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 { pub fn finish(self) -> SettingGroup {
let mut group = SettingGroup { let mut group = SettingGroup {
name: self.name, name: self.name,
@@ -353,12 +347,12 @@ impl SettingGroupBuilder {
group.bool_start_byte_offset = byte_offset; group.bool_start_byte_offset = byte_offset;
let mut predicate_number = 0;
// Then the boolean settings. // Then the boolean settings.
for s in &self.settings { for s in &self.settings {
let (default, predicate_number) = match s.specific { let default = match s.specific {
ProtoSpecificSetting::Bool(default, predicate_number) => { ProtoSpecificSetting::Bool(default) => default,
(default, predicate_number)
}
ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue, ProtoSpecificSetting::Enum(_) | ProtoSpecificSetting::Num(_) => continue,
}; };
group.settings.push(Setting { group.settings.push(Setting {
@@ -371,6 +365,7 @@ impl SettingGroupBuilder {
predicate_number, predicate_number,
}), }),
}); });
predicate_number += 1;
} }
assert!( assert!(
@@ -379,7 +374,22 @@ impl SettingGroupBuilder {
); );
group.settings_size = group.byte_size(); group.settings_size = group.byte_size();
group.predicates.extend(self.predicates); // 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;
return Predicate {
name: predicate.name,
node: predicate.node,
number,
};
}));
group.presets.extend(self.presets); group.presets.extend(self.presets);
group group

View File

@@ -11,7 +11,7 @@ use crate::shared::Definitions as SharedDefinitions;
mod instructions; mod instructions;
mod legalize; mod legalize;
fn define_settings(_shared: &SettingGroup) -> SettingGroup { fn define_settings(shared: &SettingGroup) -> SettingGroup {
let mut settings = SettingGroupBuilder::new("x86"); let mut settings = SettingGroupBuilder::new("x86");
// CPUID.01H:ECX // CPUID.01H:ECX
@@ -47,6 +47,24 @@ fn define_settings(_shared: &SettingGroup) -> SettingGroup {
settings.add_predicate("use_bmi1", predicate!(has_bmi1)); settings.add_predicate("use_bmi1", predicate!(has_bmi1));
settings.add_predicate("use_lznct", predicate!(has_lzcnt)); settings.add_predicate("use_lznct", predicate!(has_lzcnt));
// Some shared boolean values are used in x86 instruction predicates, so we need to group them
// in the same TargetIsa, for compabitibity with code generated by meta-python.
// TODO Once all the meta generation code has been migrated from Python to Rust, we can put it
// back in the shared SettingGroup, and use it in x86 instruction predicates.
let is_pic = shared.get_bool("is_pic");
let allones_funcaddrs = shared.get_bool("allones_funcaddrs");
settings.add_predicate("is_pic", predicate!(is_pic));
settings.add_predicate("not_is_pic", predicate!(!is_pic));
settings.add_predicate(
"all_ones_funcaddrs_and_not_is_pic",
predicate!(allones_funcaddrs && !is_pic),
);
settings.add_predicate(
"not_all_ones_funcaddrs_and_not_is_pic",
predicate!(!allones_funcaddrs && !is_pic),
);
settings.add_preset("baseline", preset!()); settings.add_preset("baseline", preset!());
let nehalem = settings.add_preset( let nehalem = settings.add_preset(
"nehalem", "nehalem",