[build] Move settings generation from Python to Rust code;
This commit is contained in:
committed by
Dan Gohman
parent
4c8f1e7a5a
commit
d94e027c2a
@@ -82,20 +82,12 @@ fn main() {
|
|||||||
// Now that the Python build process is complete, generate files that are
|
// Now that the Python build process is complete, generate files that are
|
||||||
// emitted by the `meta` crate.
|
// emitted by the `meta` crate.
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
let isas = meta::isa::define_all();
|
|
||||||
|
|
||||||
if let Err(err) = meta::gen_types::generate("types.rs", &out_dir) {
|
if let Err(err) = generate_meta(&out_dir) {
|
||||||
eprintln!("Error: {}", err);
|
eprintln!("Error: {}", err);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for isa in isas {
|
|
||||||
if let Err(err) = meta::gen_registers::generate(isa, "registers", &out_dir) {
|
|
||||||
eprintln!("Error: {}", err);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(_) = env::var("CRANELIFT_VERBOSE") {
|
if let Ok(_) = env::var("CRANELIFT_VERBOSE") {
|
||||||
println!(
|
println!(
|
||||||
"cargo:warning=Build step took {:?}.",
|
"cargo:warning=Build step took {:?}.",
|
||||||
@@ -105,6 +97,20 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_meta(out_dir: &str) -> Result<(), meta::error::Error> {
|
||||||
|
let shared_settings = meta::gen_settings::generate_common("new_settings.rs", &out_dir)?;
|
||||||
|
let isas = meta::isa::define_all(&shared_settings);
|
||||||
|
|
||||||
|
meta::gen_types::generate("types.rs", &out_dir)?;
|
||||||
|
|
||||||
|
for isa in &isas {
|
||||||
|
meta::gen_registers::generate(&isa, "registers", &out_dir)?;
|
||||||
|
meta::gen_settings::generate(&isa, "new_settings", &out_dir)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn identify_python() -> &'static str {
|
fn identify_python() -> &'static str {
|
||||||
for python in &["python", "python3", "python2.7"] {
|
for python in &["python", "python3", "python2.7"] {
|
||||||
if process::Command::new(python)
|
if process::Command::new(python)
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ class SettingGroup(object):
|
|||||||
precomputed predicates.
|
precomputed predicates.
|
||||||
|
|
||||||
This is the size of the byte-sized settings plus all the numbered
|
This is the size of the byte-sized settings plus all the numbered
|
||||||
predcate bits rounded up to a whole number of bytes.
|
predicate bits rounded up to a whole number of bytes.
|
||||||
"""
|
"""
|
||||||
return self.boolean_offset + (len(self.predicate_number) + 7) // 8
|
return self.boolean_offset + (len(self.predicate_number) + 7) // 8
|
||||||
|
|
||||||
|
|||||||
@@ -255,8 +255,8 @@ def gen_display(sgrp, fmt):
|
|||||||
fmt.line('Ok(())')
|
fmt.line('Ok(())')
|
||||||
|
|
||||||
|
|
||||||
def gen_constructor(sgrp, parent, fmt):
|
def gen_constructor(sgrp, fmt):
|
||||||
# type: (SettingGroup, PredContext, srcgen.Formatter) -> None
|
# type: (SettingGroup, srcgen.Formatter) -> None
|
||||||
"""
|
"""
|
||||||
Generate a Flags constructor.
|
Generate a Flags constructor.
|
||||||
"""
|
"""
|
||||||
@@ -310,7 +310,7 @@ def gen_group(sgrp, fmt):
|
|||||||
with fmt.indented('pub struct Flags {', '}'):
|
with fmt.indented('pub struct Flags {', '}'):
|
||||||
fmt.line('bytes: [u8; {}],'.format(sgrp.byte_size()))
|
fmt.line('bytes: [u8; {}],'.format(sgrp.byte_size()))
|
||||||
|
|
||||||
gen_constructor(sgrp, None, fmt)
|
gen_constructor(sgrp, fmt)
|
||||||
gen_enum_types(sgrp, fmt)
|
gen_enum_types(sgrp, fmt)
|
||||||
gen_getters(sgrp, fmt)
|
gen_getters(sgrp, fmt)
|
||||||
gen_descriptors(sgrp, fmt)
|
gen_descriptors(sgrp, fmt)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
//! Definitions for the base Cranelift language.
|
//! Definitions for the base Cranelift language.
|
||||||
|
|
||||||
|
pub mod settings;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|||||||
164
lib/codegen/meta/src/base/settings.rs
Normal file
164
lib/codegen/meta/src/base/settings.rs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
use cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||||
|
|
||||||
|
pub fn generate() -> SettingGroup {
|
||||||
|
let mut settings = SettingGroupBuilder::new("shared");
|
||||||
|
|
||||||
|
settings.add_enum(
|
||||||
|
"opt_level",
|
||||||
|
r#"
|
||||||
|
Optimization level:
|
||||||
|
|
||||||
|
- default: Very profitable optimizations enabled, none slow.
|
||||||
|
- best: Enable all optimizations
|
||||||
|
- fastest: Optimize for compile time by disabling most optimizations.
|
||||||
|
"#,
|
||||||
|
vec!["default", "best", "fastest"],
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"enable_verifier",
|
||||||
|
r#"
|
||||||
|
Run the Cranelift IR verifier at strategic times during compilation.
|
||||||
|
|
||||||
|
This makes compilation slower but catches many bugs. The verifier is
|
||||||
|
disabled by default, except when reading Cranelift IR from a text file.
|
||||||
|
"#,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Note that Cranelift doesn't currently need an is_pie flag, because PIE is
|
||||||
|
// just PIC where symbols can't be pre-empted, which can be expressed with the
|
||||||
|
// `colocated` flag on external functions and global values.
|
||||||
|
settings.add_bool(
|
||||||
|
"is_pic",
|
||||||
|
"Enable Position-Independent Code generation",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"colocated_libcalls",
|
||||||
|
r#"
|
||||||
|
Use colocated libcalls.
|
||||||
|
|
||||||
|
Generate code that assumes that libcalls can be declared "colocated",
|
||||||
|
meaning they will be defined along with the current function, such that
|
||||||
|
they can use more efficient addressing.
|
||||||
|
"#,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"avoid_div_traps",
|
||||||
|
r#"
|
||||||
|
Generate explicit checks around native division instructions to avoid
|
||||||
|
their trapping.
|
||||||
|
|
||||||
|
This is primarily used by SpiderMonkey which doesn't install a signal
|
||||||
|
handler for SIGFPE, but expects a SIGILL trap for division by zero.
|
||||||
|
|
||||||
|
On ISAs like ARM where the native division instructions don't trap,
|
||||||
|
this setting has no effect - explicit checks are always inserted.
|
||||||
|
"#,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"enable_float",
|
||||||
|
r#"
|
||||||
|
Enable the use of floating-point instructions
|
||||||
|
|
||||||
|
Disabling use of floating-point instructions is not yet implemented.
|
||||||
|
"#,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"enable_nan_canonicalization",
|
||||||
|
r#"
|
||||||
|
Enable NaN canonicalization
|
||||||
|
|
||||||
|
This replaces NaNs with a single canonical value, for users requiring
|
||||||
|
entirely deterministic WebAssembly computation. This is not required
|
||||||
|
by the WebAssembly spec, so it is not enabled by default.
|
||||||
|
"#,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool("enable_simd", "Enable the use of SIMD instructions.", true);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"enable_atomics",
|
||||||
|
"Enable the use of atomic instructions",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Settings specific to the `baldrdash` calling convention.
|
||||||
|
|
||||||
|
settings.add_num(
|
||||||
|
"baldrdash_prologue_words",
|
||||||
|
r#"
|
||||||
|
Number of pointer-sized words pushed by the baldrdash prologue.
|
||||||
|
|
||||||
|
Functions with the `baldrdash` calling convention don't generate their
|
||||||
|
own prologue and epilogue. They depend on externally generated code
|
||||||
|
that pushes a fixed number of words in the prologue and restores them
|
||||||
|
in the epilogue.
|
||||||
|
|
||||||
|
This setting configures the number of pointer-sized words pushed on the
|
||||||
|
stack when the Cranelift-generated code is entered. This includes the
|
||||||
|
pushed return address on x86.
|
||||||
|
"#,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
// BaldrMonkey requires that not-yet-relocated function addresses be encoded
|
||||||
|
// as all-ones bitpatterns.
|
||||||
|
settings.add_bool(
|
||||||
|
"allones_funcaddrs",
|
||||||
|
"Emit not-yet-relocated function addresses as all-ones bit patterns.",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Stack probing options.
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"probestack_enabled",
|
||||||
|
r#"
|
||||||
|
Enable the use of stack probes, for calling conventions which support this
|
||||||
|
functionality.
|
||||||
|
"#,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"probestack_func_adjusts_sp",
|
||||||
|
r#"
|
||||||
|
Set this to true of the stack probe function modifies the stack pointer
|
||||||
|
itself.
|
||||||
|
"#,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_num(
|
||||||
|
"probestack_size_log2",
|
||||||
|
r#"
|
||||||
|
The log2 of the size of the stack guard region.
|
||||||
|
|
||||||
|
Stack frames larger than this size will have stack overflow checked
|
||||||
|
by calling the probestack function.
|
||||||
|
|
||||||
|
The default is 12, which translates to a size of 4096.
|
||||||
|
"#,
|
||||||
|
12,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Jump table options.
|
||||||
|
|
||||||
|
settings.add_bool(
|
||||||
|
"jump_tables_enabled",
|
||||||
|
"Enable the use of jump tables in generated machine code.",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.finish()
|
||||||
|
}
|
||||||
@@ -3,19 +3,22 @@ use cranelift_entity::PrimaryMap;
|
|||||||
use super::regs::{
|
use super::regs::{
|
||||||
RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex, RegClassProto,
|
RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex, RegClassProto,
|
||||||
};
|
};
|
||||||
|
use super::settings::SettingGroup;
|
||||||
|
|
||||||
pub struct TargetIsa {
|
pub struct TargetIsa {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
pub reg_banks: PrimaryMap<RegBankIndex, RegBank>,
|
pub reg_banks: PrimaryMap<RegBankIndex, RegBank>,
|
||||||
pub reg_classes: PrimaryMap<RegClassIndex, RegClass>,
|
pub reg_classes: PrimaryMap<RegClassIndex, RegClass>,
|
||||||
|
pub settings: SettingGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsa {
|
impl TargetIsa {
|
||||||
pub fn new(name: &'static str) -> Self {
|
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
reg_banks: PrimaryMap::new(),
|
reg_banks: PrimaryMap::new(),
|
||||||
reg_classes: PrimaryMap::new(),
|
reg_classes: PrimaryMap::new(),
|
||||||
|
settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,9 +28,9 @@ pub struct TargetIsaBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TargetIsaBuilder {
|
impl TargetIsaBuilder {
|
||||||
pub fn new(name: &'static str) -> Self {
|
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
|
||||||
Self {
|
Self {
|
||||||
isa: TargetIsa::new(name),
|
isa: TargetIsa::new(name, settings),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,38 @@
|
|||||||
|
|
||||||
pub mod isa;
|
pub mod isa;
|
||||||
pub mod regs;
|
pub mod regs;
|
||||||
|
pub mod settings;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
/// A macro that converts boolean settings into predicates to look more natural.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! predicate {
|
||||||
|
($a:ident && $($b:tt)*) => {
|
||||||
|
PredicateNode::And(Box::new($a.into()), Box::new(predicate!($($b)*)))
|
||||||
|
};
|
||||||
|
($a:ident) => {
|
||||||
|
$a.into()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! preset {
|
||||||
|
() => {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
($($x:ident)&&*) => {
|
||||||
|
{
|
||||||
|
let mut v = Vec::new();
|
||||||
|
$(
|
||||||
|
v.push($x.into());
|
||||||
|
)*
|
||||||
|
v
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert the string `s` to CamelCase.
|
/// Convert the string `s` to CamelCase.
|
||||||
fn _camel_case(s: &str) -> String {
|
pub fn camel_case(s: &str) -> String {
|
||||||
let mut output_chars = String::with_capacity(s.len());
|
let mut output_chars = String::with_capacity(s.len());
|
||||||
|
|
||||||
let mut capitalize = true;
|
let mut capitalize = true;
|
||||||
@@ -30,7 +58,7 @@ fn _camel_case(s: &str) -> String {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::_camel_case as camel_case;
|
use super::camel_case;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn camel_case_works() {
|
fn camel_case_works() {
|
||||||
|
|||||||
385
lib/codegen/meta/src/cdsl/settings.rs
Normal file
385
lib/codegen/meta/src/cdsl/settings.rs
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
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 (l_mask, 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(group_name, bool_name) => {
|
||||||
|
format!("{}.{}()", group_name, bool_name)
|
||||||
|
}
|
||||||
|
PredicateNode::And(lhs, 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
|
||||||
|
}
|
||||||
|
}
|
||||||
50
lib/codegen/meta/src/constant_hash.rs
Normal file
50
lib/codegen/meta/src/constant_hash.rs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
pub fn simple_hash(s: &str) -> usize {
|
||||||
|
let mut h: u32 = 5381;
|
||||||
|
for c in s.chars() {
|
||||||
|
h = (h ^ c as u32).wrapping_add(h.rotate_right(6));
|
||||||
|
}
|
||||||
|
h as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute an open addressed, quadratically probed hash table containing
|
||||||
|
/// `items`. The returned table is a list containing the elements of the
|
||||||
|
/// iterable `items` and `None` in unused slots.
|
||||||
|
pub fn generate_table<T, H: Fn(&T) -> usize>(items: &Vec<T>, hash_function: H) -> Vec<Option<&T>> {
|
||||||
|
let size = (1.20 * items.len() as f64) as usize;
|
||||||
|
// TODO do we really need the multiply by two here?
|
||||||
|
let size = if size.is_power_of_two() {
|
||||||
|
size * 2
|
||||||
|
} else {
|
||||||
|
size.next_power_of_two()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut table: Vec<Option<&T>> = Vec::new();
|
||||||
|
table.resize(size, None);
|
||||||
|
|
||||||
|
for i in items {
|
||||||
|
let mut h = hash_function(i) % size;
|
||||||
|
let mut s = 0;
|
||||||
|
while table[h].is_some() {
|
||||||
|
s += 1;
|
||||||
|
h = (h + s) % size;
|
||||||
|
}
|
||||||
|
table[h] = Some(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
table
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_generate_table() {
|
||||||
|
let v = vec!["Hello".to_string(), "world".to_string()];
|
||||||
|
let table = generate_table(&v, |s| simple_hash(&s));
|
||||||
|
assert_eq!(
|
||||||
|
table,
|
||||||
|
vec![
|
||||||
|
None,
|
||||||
|
Some(&"Hello".to_string()),
|
||||||
|
Some(&"world".to_string()),
|
||||||
|
None
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -78,7 +78,7 @@ fn gen_regbank_units(reg_bank: &RegBank, fmt: &mut Formatter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) -> Result<(), error::Error> {
|
fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) {
|
||||||
// Emit RegInfo.
|
// Emit RegInfo.
|
||||||
fmt.line("pub static INFO: RegInfo = RegInfo {");
|
fmt.line("pub static INFO: RegInfo = RegInfo {");
|
||||||
|
|
||||||
@@ -128,13 +128,11 @@ fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) -> Result<(), error::Error> {
|
|||||||
fmt.line("}")
|
fmt.line("}")
|
||||||
});
|
});
|
||||||
fmt.line("}");
|
fmt.line("}");
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(isa: TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> {
|
pub fn generate(isa: &TargetIsa, base_filename: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||||
let mut fmt = Formatter::new();
|
let mut fmt = Formatter::new();
|
||||||
gen_isa(&isa, &mut fmt)?;
|
gen_isa(&isa, &mut fmt);
|
||||||
fmt.update_file(&format!("{}-{}.rs", base_filename, isa.name), out_dir)?;
|
fmt.update_file(&format!("{}-{}.rs", base_filename, isa.name), out_dir)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
447
lib/codegen/meta/src/gen_settings.rs
Normal file
447
lib/codegen/meta/src/gen_settings.rs
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
use base;
|
||||||
|
use cdsl::camel_case;
|
||||||
|
use cdsl::isa::TargetIsa;
|
||||||
|
use cdsl::settings::{BoolSetting, Predicate, Preset, Setting, SettingGroup, SpecificSetting};
|
||||||
|
use constant_hash::{generate_table, simple_hash};
|
||||||
|
use error;
|
||||||
|
use srcgen::{Formatter, Match};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use unique_table::UniqueTable;
|
||||||
|
|
||||||
|
enum ParentGroup {
|
||||||
|
None,
|
||||||
|
Shared,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits the constructor of the Flags structure.
|
||||||
|
fn gen_constructor(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
|
||||||
|
let args = match parent {
|
||||||
|
ParentGroup::None => "builder: Builder",
|
||||||
|
ParentGroup::Shared => "shared: &settings::Flags, builder: Builder",
|
||||||
|
};
|
||||||
|
fmt.line("impl Flags {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.doc_comment(&format!("Create flags {} settings group.", group.name));
|
||||||
|
fmt.line("#[allow(unused_variables)]");
|
||||||
|
fmt.line(&format!("pub fn new({}) -> Self {{", args));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!(
|
||||||
|
"let bvec = builder.state_for(\"{}\");",
|
||||||
|
group.name
|
||||||
|
));
|
||||||
|
fmt.line(&format!(
|
||||||
|
"let mut {} = Self {{ bytes: [0; {}] }};",
|
||||||
|
group.name,
|
||||||
|
group.byte_size()
|
||||||
|
));
|
||||||
|
fmt.line(&format!(
|
||||||
|
"debug_assert_eq!(bvec.len(), {});",
|
||||||
|
group.settings_size
|
||||||
|
));
|
||||||
|
fmt.line(&format!(
|
||||||
|
"{}.bytes[0..{}].copy_from_slice(&bvec);",
|
||||||
|
group.name, group.settings_size
|
||||||
|
));
|
||||||
|
|
||||||
|
// Now compute the predicates.
|
||||||
|
for p in &group.predicates {
|
||||||
|
fmt.comment(&format!("Precompute #{}.", p.number));
|
||||||
|
fmt.line(&format!("if {} {{", p.render(group)));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!(
|
||||||
|
"{}.bytes[{}] |= 1 << {};",
|
||||||
|
group.name,
|
||||||
|
group.bool_start_byte_offset + p.number / 8,
|
||||||
|
p.number % 8
|
||||||
|
));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.line(group.name);
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit Display and FromStr implementations for enum settings.
|
||||||
|
fn gen_to_and_from_str(name: &str, values: &[&'static str], fmt: &mut Formatter) {
|
||||||
|
fmt.line(&format!("impl fmt::Display for {} {{", name));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("f.write_str(match *self {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for v in values.iter() {
|
||||||
|
fmt.line(&format!("{}::{} => \"{}\",", name, camel_case(v), v));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("})");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
|
||||||
|
fmt.line(&format!("impl str::FromStr for {} {{", name));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("type Err = ();");
|
||||||
|
fmt.line("fn from_str(s: &str) -> Result<Self, Self::Err> {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("match s {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for v in values.iter() {
|
||||||
|
fmt.line(&format!("\"{}\" => Ok({}::{}),", v, name, camel_case(v)));
|
||||||
|
}
|
||||||
|
fmt.line("_ => Err(()),");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit real enum for the Enum settings.
|
||||||
|
fn gen_enum_types(group: &SettingGroup, fmt: &mut Formatter) {
|
||||||
|
for setting in group.settings.iter() {
|
||||||
|
let values = match setting.specific {
|
||||||
|
SpecificSetting::Bool(_) | SpecificSetting::Num(_) => continue,
|
||||||
|
SpecificSetting::Enum(ref values) => values,
|
||||||
|
};
|
||||||
|
let name = camel_case(setting.name);
|
||||||
|
|
||||||
|
fmt.doc_comment(&format!("Values for `{}.{}`.", group.name, setting.name));
|
||||||
|
fmt.line("#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]");
|
||||||
|
fmt.line(&format!("pub enum {} {{", name));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for v in values.iter() {
|
||||||
|
fmt.doc_comment(&format!("`{}`.", v));
|
||||||
|
fmt.line(&format!("{},", camel_case(v)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
|
||||||
|
gen_to_and_from_str(&name, values, fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emit a getter function for `setting`.
|
||||||
|
fn gen_getter(setting: &Setting, fmt: &mut Formatter) {
|
||||||
|
fmt.doc_comment(setting.comment);
|
||||||
|
match setting.specific {
|
||||||
|
SpecificSetting::Bool(BoolSetting {
|
||||||
|
predicate_number, ..
|
||||||
|
}) => {
|
||||||
|
fmt.line(&format!("pub fn {}(&self) -> bool {{", setting.name));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("self.numbered_predicate({})", predicate_number));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
SpecificSetting::Enum(ref values) => {
|
||||||
|
let ty = camel_case(setting.name);
|
||||||
|
fmt.line(&format!("pub fn {}(&self) -> {} {{", setting.name, ty));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
let mut m = Match::new(format!("self.bytes[{}]", setting.byte_offset));
|
||||||
|
for (i, v) in values.iter().enumerate() {
|
||||||
|
m.arm(
|
||||||
|
format!("{}", i),
|
||||||
|
vec![],
|
||||||
|
format!("{}::{}", ty, camel_case(v)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
m.arm("_", vec![], "panic!(\"Invalid enum value\")");
|
||||||
|
fmt.add_match(m);
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
SpecificSetting::Num(_) => {
|
||||||
|
fmt.line(&format!("pub fn {}(&self) -> u8 {{", setting.name));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("self.bytes[{}]", setting.byte_offset));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_pred_getter(predicate: &Predicate, group: &SettingGroup, fmt: &mut Formatter) {
|
||||||
|
fmt.doc_comment(&format!(
|
||||||
|
"Computed predicate `{}`.",
|
||||||
|
predicate.render(group)
|
||||||
|
));
|
||||||
|
fmt.line(&format!("pub fn {}(&self) -> bool {{", predicate.name));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("self.numbered_predicate({})", predicate.number));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits getters for each setting value.
|
||||||
|
fn gen_getters(group: &SettingGroup, fmt: &mut Formatter) {
|
||||||
|
fmt.doc_comment("User-defined settings.");
|
||||||
|
fmt.line("#[allow(dead_code)]");
|
||||||
|
fmt.line("impl Flags {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.doc_comment("Get a view of the boolean predicates.");
|
||||||
|
fmt.line("pub fn predicate_view(&self) -> ::settings::PredicateView {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!(
|
||||||
|
"::settings::PredicateView::new(&self.bytes[{}..])",
|
||||||
|
group.bool_start_byte_offset
|
||||||
|
));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
|
||||||
|
if group.settings.len() > 0 {
|
||||||
|
fmt.doc_comment("Dynamic numbered predicate getter.");
|
||||||
|
fmt.line("fn numbered_predicate(&self, p: usize) -> bool {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!(
|
||||||
|
"self.bytes[{} + p / 8] & (1 << (p % 8)) != 0",
|
||||||
|
group.bool_start_byte_offset
|
||||||
|
));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
for setting in &group.settings {
|
||||||
|
gen_getter(&setting, fmt);
|
||||||
|
}
|
||||||
|
for predicate in &group.predicates {
|
||||||
|
gen_pred_getter(&predicate, &group, fmt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq)]
|
||||||
|
enum SettingOrPreset<'a> {
|
||||||
|
Setting(&'a Setting),
|
||||||
|
Preset(&'a Preset),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SettingOrPreset<'a> {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
SettingOrPreset::Setting(s) => s.name,
|
||||||
|
SettingOrPreset::Preset(p) => p.name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits DESCRIPTORS, ENUMERATORS, HASH_TABLE and PRESETS.
|
||||||
|
fn gen_descriptors(group: &SettingGroup, fmt: &mut Formatter) {
|
||||||
|
let mut enum_table: UniqueTable<&'static str> = UniqueTable::new();
|
||||||
|
|
||||||
|
let mut descriptor_index_map: HashMap<SettingOrPreset, usize> = HashMap::new();
|
||||||
|
|
||||||
|
// Generate descriptors.
|
||||||
|
fmt.line(&format!(
|
||||||
|
"static DESCRIPTORS: [detail::Descriptor; {}] = [",
|
||||||
|
group.settings.len() + group.presets.len()
|
||||||
|
));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for (idx, setting) in group.settings.iter().enumerate() {
|
||||||
|
fmt.line("detail::Descriptor {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("name: \"{}\",", setting.name));
|
||||||
|
fmt.line(&format!("offset: {},", setting.byte_offset));
|
||||||
|
match &setting.specific {
|
||||||
|
SpecificSetting::Bool(BoolSetting { bit_offset, .. }) => {
|
||||||
|
fmt.line(&format!(
|
||||||
|
"detail: detail::Detail::Bool {{ bit: {} }},",
|
||||||
|
bit_offset
|
||||||
|
));
|
||||||
|
}
|
||||||
|
SpecificSetting::Enum(values) => {
|
||||||
|
let offset = enum_table.add(values);
|
||||||
|
fmt.line(&format!(
|
||||||
|
"detail: detail::Detail::Enum {{ last: {}, enumerators: {} }},",
|
||||||
|
values.len() - 1,
|
||||||
|
offset
|
||||||
|
));
|
||||||
|
}
|
||||||
|
SpecificSetting::Num(_) => {
|
||||||
|
fmt.line("detail: detail::Detail::Num,");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor_index_map.insert(SettingOrPreset::Setting(setting), idx);
|
||||||
|
});
|
||||||
|
fmt.line("},");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, preset) in group.presets.iter().enumerate() {
|
||||||
|
fmt.line("detail::Descriptor {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("name: \"{}\",", preset.name));
|
||||||
|
fmt.line(&format!("offset: {},", (idx as u8) * group.settings_size));
|
||||||
|
fmt.line("detail: detail::Detail::Preset,");
|
||||||
|
});
|
||||||
|
fmt.line("},");
|
||||||
|
|
||||||
|
descriptor_index_map.insert(SettingOrPreset::Preset(preset), idx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("];");
|
||||||
|
|
||||||
|
// Generate enumerators.
|
||||||
|
fmt.line(&format!(
|
||||||
|
"static ENUMERATORS: [&str; {}] = [",
|
||||||
|
enum_table.len()
|
||||||
|
));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for enum_val in enum_table.iter() {
|
||||||
|
fmt.line(&format!("\"{}\",", enum_val));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("];");
|
||||||
|
|
||||||
|
// Generate hash table.
|
||||||
|
let mut hash_entries: Vec<SettingOrPreset> = Vec::new();
|
||||||
|
hash_entries.extend(
|
||||||
|
group
|
||||||
|
.settings
|
||||||
|
.iter()
|
||||||
|
.map(|x| SettingOrPreset::Setting(x))
|
||||||
|
.collect::<Vec<SettingOrPreset>>(),
|
||||||
|
);
|
||||||
|
hash_entries.extend(
|
||||||
|
group
|
||||||
|
.presets
|
||||||
|
.iter()
|
||||||
|
.map(|x| SettingOrPreset::Preset(x))
|
||||||
|
.collect::<Vec<SettingOrPreset>>(),
|
||||||
|
);
|
||||||
|
let hash_table = generate_table(&hash_entries, |entry| simple_hash(entry.name()));
|
||||||
|
fmt.line(&format!(
|
||||||
|
"static HASH_TABLE: [u16; {}] = [",
|
||||||
|
hash_table.len()
|
||||||
|
));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for h in &hash_table {
|
||||||
|
match h {
|
||||||
|
Some(setting_or_preset) => fmt.line(&format!(
|
||||||
|
"{},",
|
||||||
|
&descriptor_index_map
|
||||||
|
.get(setting_or_preset)
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
)),
|
||||||
|
None => fmt.line("0xffff,"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("];");
|
||||||
|
|
||||||
|
// Generate presets.
|
||||||
|
fmt.line(&format!(
|
||||||
|
"static PRESETS: [(u8, u8); {}] = [",
|
||||||
|
group.presets.len()
|
||||||
|
));
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
for preset in &group.presets {
|
||||||
|
fmt.comment(preset.name);
|
||||||
|
for (mask, value) in preset.layout(&group) {
|
||||||
|
fmt.line(&format!("(0b{:08b}, 0b{:08b}),", mask, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fmt.line("];");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_template(group: &SettingGroup, fmt: &mut Formatter) {
|
||||||
|
let mut default_bytes: Vec<u8> = Vec::new();
|
||||||
|
default_bytes.resize(group.settings_size as usize, 0);
|
||||||
|
for setting in &group.settings {
|
||||||
|
*default_bytes.get_mut(setting.byte_offset as usize).unwrap() |= setting.default_byte();
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_bytes: Vec<String> = default_bytes
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("{:#04x}", x))
|
||||||
|
.collect();
|
||||||
|
let default_bytes_str = default_bytes.join(", ");
|
||||||
|
|
||||||
|
fmt.line("static TEMPLATE: detail::Template = detail::Template {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("name: \"{}\",", group.name));
|
||||||
|
fmt.line("descriptors: &DESCRIPTORS,");
|
||||||
|
fmt.line("enumerators: &ENUMERATORS,");
|
||||||
|
fmt.line("hash_table: &HASH_TABLE,");
|
||||||
|
fmt.line(&format!("defaults: &[{}],", default_bytes_str));
|
||||||
|
fmt.line("presets: &PRESETS,");
|
||||||
|
});
|
||||||
|
fmt.line("};");
|
||||||
|
|
||||||
|
fmt.doc_comment(&format!(
|
||||||
|
"Create a `settings::Builder` for the {} settings group.",
|
||||||
|
group.name
|
||||||
|
));
|
||||||
|
fmt.line("pub fn builder() -> Builder {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("Builder::new(&TEMPLATE)");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_display(group: &SettingGroup, fmt: &mut Formatter) {
|
||||||
|
fmt.line("impl fmt::Display for Flags {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("writeln!(f, \"[{}]\")?;", group.name));
|
||||||
|
fmt.line("for d in &DESCRIPTORS {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("if !d.detail.is_preset() {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line("write!(f, \"{} = \", d.name)?;");
|
||||||
|
fmt.line(
|
||||||
|
"TEMPLATE.format_toml_value(d.detail, self.bytes[d.offset as usize], f)?;",
|
||||||
|
);
|
||||||
|
fmt.line("writeln!(f)?;");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
fmt.line("Ok(())");
|
||||||
|
});
|
||||||
|
fmt.line("}")
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_group(group: &SettingGroup, parent: ParentGroup, fmt: &mut Formatter) {
|
||||||
|
// Generate struct.
|
||||||
|
fmt.line("#[derive(Clone)]");
|
||||||
|
fmt.doc_comment(&format!("Flags group `{}`.", group.name));
|
||||||
|
fmt.line("pub struct Flags {");
|
||||||
|
fmt.indent(|fmt| {
|
||||||
|
fmt.line(&format!("bytes: [u8; {}],", group.byte_size()));
|
||||||
|
});
|
||||||
|
fmt.line("}");
|
||||||
|
|
||||||
|
gen_constructor(group, parent, fmt);
|
||||||
|
gen_enum_types(group, fmt);
|
||||||
|
gen_getters(group, fmt);
|
||||||
|
gen_descriptors(group, fmt);
|
||||||
|
gen_template(group, fmt);
|
||||||
|
gen_display(group, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_common(filename: &str, out_dir: &str) -> Result<SettingGroup, error::Error> {
|
||||||
|
let settings = base::settings::generate();
|
||||||
|
let mut fmt = Formatter::new();
|
||||||
|
gen_group(&settings, ParentGroup::None, &mut fmt);
|
||||||
|
fmt.update_file(filename, out_dir)?;
|
||||||
|
Ok(settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate(isa: &TargetIsa, prefix: &str, out_dir: &str) -> Result<(), error::Error> {
|
||||||
|
let mut fmt = Formatter::new();
|
||||||
|
gen_group(&isa.settings, ParentGroup::Shared, &mut fmt);
|
||||||
|
fmt.update_file(&format!("{}-{}.rs", prefix, isa.name), out_dir)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||||
|
use cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||||
|
|
||||||
pub fn define() -> TargetIsa {
|
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||||
let mut isa = TargetIsaBuilder::new("arm32");
|
let setting = SettingGroupBuilder::new("arm32");
|
||||||
|
setting.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||||
|
let mut isa = TargetIsaBuilder::new("arm32", define_settings(shared_settings));
|
||||||
|
|
||||||
let builder = RegBankBuilder::new("FloatRegs", "s")
|
let builder = RegBankBuilder::new("FloatRegs", "s")
|
||||||
.units(64)
|
.units(64)
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||||
|
use cdsl::settings::{SettingGroup, SettingGroupBuilder};
|
||||||
|
|
||||||
pub fn define() -> TargetIsa {
|
fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||||
let mut isa = TargetIsaBuilder::new("arm64");
|
let setting = SettingGroupBuilder::new("arm64");
|
||||||
|
setting.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||||
|
let mut isa = TargetIsaBuilder::new("arm64", define_settings(shared_settings));
|
||||||
|
|
||||||
// The `x31` regunit serves as the stack pointer / zero register depending on context. We
|
// The `x31` regunit serves as the stack pointer / zero register depending on context. We
|
||||||
// reserve it and don't model the difference.
|
// reserve it and don't model the difference.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use cdsl::isa::TargetIsa;
|
use cdsl::isa::TargetIsa;
|
||||||
|
use cdsl::settings::SettingGroup;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
mod arm32;
|
mod arm32;
|
||||||
@@ -61,11 +62,11 @@ impl fmt::Display for Isa {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn define_all() -> Vec<TargetIsa> {
|
pub fn define_all(shared_settings: &SettingGroup) -> Vec<TargetIsa> {
|
||||||
vec![
|
vec![
|
||||||
riscv::define(),
|
riscv::define(shared_settings),
|
||||||
arm32::define(),
|
arm32::define(shared_settings),
|
||||||
arm64::define(),
|
arm64::define(shared_settings),
|
||||||
x86::define(),
|
x86::define(shared_settings),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,61 @@
|
|||||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||||
|
use cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
||||||
|
|
||||||
pub fn define() -> TargetIsa {
|
fn define_settings(shared: &SettingGroup) -> SettingGroup {
|
||||||
let mut isa = TargetIsaBuilder::new("riscv");
|
let mut setting = SettingGroupBuilder::new("riscv");
|
||||||
|
|
||||||
|
let supports_m = setting.add_bool(
|
||||||
|
"supports_m",
|
||||||
|
"CPU supports the 'M' extension (mul/div)",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let supports_a = setting.add_bool(
|
||||||
|
"supports_a",
|
||||||
|
"CPU supports the 'A' extension (atomics)",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let supports_f = setting.add_bool(
|
||||||
|
"supports_f",
|
||||||
|
"CPU supports the 'F' extension (float)",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let supports_d = setting.add_bool(
|
||||||
|
"supports_d",
|
||||||
|
"CPU supports the 'D' extension (double)",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
let enable_m = setting.add_bool(
|
||||||
|
"enable_m",
|
||||||
|
"Enable the use of 'M' instructions if available",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
setting.add_bool(
|
||||||
|
"enable_e",
|
||||||
|
"Enable the 'RV32E' instruction set with only 16 registers",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
let shared_enable_atomics = shared.get_bool("enable_atomics");
|
||||||
|
let shared_enable_float = shared.get_bool("enable_float");
|
||||||
|
let shared_enable_simd = shared.get_bool("enable_simd");
|
||||||
|
|
||||||
|
setting.add_predicate("use_m", predicate!(supports_m && enable_m));
|
||||||
|
setting.add_predicate("use_a", predicate!(supports_a && shared_enable_atomics));
|
||||||
|
setting.add_predicate("use_f", predicate!(supports_f && shared_enable_float));
|
||||||
|
setting.add_predicate("use_d", predicate!(supports_d && shared_enable_float));
|
||||||
|
setting.add_predicate(
|
||||||
|
"full_float",
|
||||||
|
predicate!(shared_enable_simd && supports_f && supports_d),
|
||||||
|
);
|
||||||
|
|
||||||
|
setting.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||||
|
let mut isa = TargetIsaBuilder::new("riscv", define_settings(shared_settings));
|
||||||
|
|
||||||
let builder = RegBankBuilder::new("IntRegs", "x")
|
let builder = RegBankBuilder::new("IntRegs", "x")
|
||||||
.units(32)
|
.units(32)
|
||||||
|
|||||||
@@ -1,9 +1,74 @@
|
|||||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||||
|
use cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};
|
||||||
|
|
||||||
pub fn define() -> TargetIsa {
|
pub fn define_settings(_shared: &SettingGroup) -> SettingGroup {
|
||||||
let mut isa = TargetIsaBuilder::new("x86");
|
let mut settings = SettingGroupBuilder::new("x86");
|
||||||
|
|
||||||
|
// CPUID.01H:ECX
|
||||||
|
let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
|
||||||
|
let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
|
||||||
|
let has_sse41 = settings.add_bool("has_sse41", "SSE4.1: CPUID.01H:ECX.SSE4_1[bit 19]", false);
|
||||||
|
let has_sse42 = settings.add_bool("has_sse42", "SSE4.2: CPUID.01H:ECX.SSE4_2[bit 20]", false);
|
||||||
|
let has_popcnt = settings.add_bool("has_popcnt", "POPCNT: CPUID.01H:ECX.POPCNT[bit 23]", false);
|
||||||
|
settings.add_bool("has_avx", "AVX: CPUID.01H:ECX.AVX[bit 28]", false);
|
||||||
|
|
||||||
|
// CPUID.(EAX=07H, ECX=0H):EBX
|
||||||
|
let has_bmi1 = settings.add_bool(
|
||||||
|
"has_bmi1",
|
||||||
|
"BMI1: CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let has_bmi2 = settings.add_bool(
|
||||||
|
"has_bmi2",
|
||||||
|
"BMI2: CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
// CPUID.EAX=80000001H:ECX
|
||||||
|
let has_lzcnt = settings.add_bool(
|
||||||
|
"has_lzcnt",
|
||||||
|
"LZCNT: CPUID.EAX=80000001H:ECX.LZCNT[bit 5]",
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.add_predicate("use_sse41", predicate!(has_sse41));
|
||||||
|
settings.add_predicate("use_sse42", predicate!(has_sse41 && has_sse42));
|
||||||
|
settings.add_predicate("use_popcnt", predicate!(has_popcnt && has_sse42));
|
||||||
|
settings.add_predicate("use_bmi1", predicate!(has_bmi1));
|
||||||
|
settings.add_predicate("use_lznct", predicate!(has_lzcnt));
|
||||||
|
|
||||||
|
settings.add_preset("baseline", preset!());
|
||||||
|
let nehalem = settings.add_preset(
|
||||||
|
"nehalem",
|
||||||
|
preset!(has_sse3 && has_ssse3 && has_sse41 && has_sse42 && has_popcnt),
|
||||||
|
);
|
||||||
|
let haswell = settings.add_preset(
|
||||||
|
"haswell",
|
||||||
|
preset!(nehalem && has_bmi1 && has_bmi2 && has_lzcnt),
|
||||||
|
);
|
||||||
|
let broadwell = settings.add_preset("broadwell", preset!(haswell));
|
||||||
|
let skylake = settings.add_preset("skylake", preset!(broadwell));
|
||||||
|
let cannonlake = settings.add_preset("cannonlake", preset!(skylake));
|
||||||
|
settings.add_preset("icelake", preset!(cannonlake));
|
||||||
|
settings.add_preset(
|
||||||
|
"znver1",
|
||||||
|
preset!(
|
||||||
|
has_sse3
|
||||||
|
&& has_ssse3
|
||||||
|
&& has_sse41
|
||||||
|
&& has_sse42
|
||||||
|
&& has_popcnt
|
||||||
|
&& has_bmi1
|
||||||
|
&& has_bmi2
|
||||||
|
&& has_lzcnt
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
settings.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn define_registers(isa: &mut TargetIsaBuilder) {
|
||||||
let builder = RegBankBuilder::new("IntRegs", "r")
|
let builder = RegBankBuilder::new("IntRegs", "r")
|
||||||
.units(16)
|
.units(16)
|
||||||
.names(vec!["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"])
|
.names(vec!["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"])
|
||||||
@@ -38,6 +103,14 @@ pub fn define() -> TargetIsa {
|
|||||||
|
|
||||||
let builder = RegClassBuilder::subclass_of("FPR8", fpr, 0, 8);
|
let builder = RegClassBuilder::subclass_of("FPR8", fpr, 0, 8);
|
||||||
isa.add_reg_class(builder);
|
isa.add_reg_class(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn define(shared_settings: &SettingGroup) -> TargetIsa {
|
||||||
|
let settings = define_settings(shared_settings);
|
||||||
|
|
||||||
|
let mut isa = TargetIsaBuilder::new("x86", settings);
|
||||||
|
|
||||||
|
define_registers(&mut isa);
|
||||||
|
|
||||||
isa.finish()
|
isa.finish()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cranelift_entity;
|
extern crate cranelift_entity;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod cdsl;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod gen_registers;
|
pub mod gen_registers;
|
||||||
|
pub mod gen_settings;
|
||||||
pub mod gen_types;
|
pub mod gen_types;
|
||||||
pub mod isa;
|
pub mod isa;
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
mod cdsl;
|
mod constant_hash;
|
||||||
mod srcgen;
|
mod srcgen;
|
||||||
|
mod unique_table;
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ impl Formatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a comment line.
|
/// Add a comment line.
|
||||||
pub fn _comment(&mut self, s: &str) {
|
pub fn comment(&mut self, s: &str) {
|
||||||
let commented_line = format!("// {}", s);
|
let commented_line = format!("// {}", s);
|
||||||
self.line(&commented_line);
|
self.line(&commented_line);
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ match x {
|
|||||||
let mut fmt = Formatter::new();
|
let mut fmt = Formatter::new();
|
||||||
fmt.line("Hello line 1");
|
fmt.line("Hello line 1");
|
||||||
fmt.indent_push();
|
fmt.indent_push();
|
||||||
fmt._comment("Nested comment");
|
fmt.comment("Nested comment");
|
||||||
fmt.indent_pop();
|
fmt.indent_pop();
|
||||||
fmt.line("Back home again");
|
fmt.line("Back home again");
|
||||||
let expected_lines = vec![
|
let expected_lines = vec![
|
||||||
|
|||||||
68
lib/codegen/meta/src/unique_table.rs
Normal file
68
lib/codegen/meta/src/unique_table.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use std::slice;
|
||||||
|
|
||||||
|
/// A table of sequences which tries to avoid common subsequences.
|
||||||
|
pub struct UniqueTable<T: PartialEq + Clone> {
|
||||||
|
table: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq + Clone> UniqueTable<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { table: Vec::new() }
|
||||||
|
}
|
||||||
|
pub fn add(&mut self, values: &Vec<T>) -> usize {
|
||||||
|
if let Some(offset) = find_subsequence(values, &self.table) {
|
||||||
|
offset
|
||||||
|
} else {
|
||||||
|
let offset = self.table.len();
|
||||||
|
self.table.extend((*values).clone());
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.table.len()
|
||||||
|
}
|
||||||
|
pub fn iter(&self) -> slice::Iter<T> {
|
||||||
|
self.table.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to find the subsequence `sub` in the `whole` sequence. Returns None if
|
||||||
|
/// it's not been found, or Some(index) if it has been. Naive implementation
|
||||||
|
/// until proven we need something better.
|
||||||
|
fn find_subsequence<T: PartialEq>(sub: &Vec<T>, whole: &Vec<T>) -> Option<usize> {
|
||||||
|
assert!(sub.len() > 0);
|
||||||
|
// We want i + sub.len() <= whole.len(), i.e. i < whole.len() + 1 - sub.len().
|
||||||
|
if whole.len() < sub.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let max = whole.len() + 1 - sub.len();
|
||||||
|
for i in 0..max {
|
||||||
|
let mut found: Option<usize> = Some(i);
|
||||||
|
for j in 0..sub.len() {
|
||||||
|
if sub[j] != whole[i + j] {
|
||||||
|
found = None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found.is_some() {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find_subsequence() {
|
||||||
|
assert_eq!(find_subsequence(&vec![1], &vec![4]), None);
|
||||||
|
assert_eq!(find_subsequence(&vec![1], &vec![1]), Some(0));
|
||||||
|
assert_eq!(find_subsequence(&vec![1, 2], &vec![1]), None);
|
||||||
|
assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 2]), Some(0));
|
||||||
|
assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 3]), None);
|
||||||
|
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 2]), Some(1));
|
||||||
|
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1]), None);
|
||||||
|
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1, 2]), Some(3));
|
||||||
|
assert_eq!(
|
||||||
|
find_subsequence(&vec![1, 1, 3], &vec![1, 1, 1, 3, 3]),
|
||||||
|
Some(1)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ pub fn probe<K: Copy + Eq, T: Table<K> + ?Sized>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A primitive hash function for matching opcodes.
|
/// A primitive hash function for matching opcodes.
|
||||||
/// Must match `lib/codegen/meta-python/constant_hash.py`.
|
/// Must match `lib/codegen/meta-python/constant_hash.py` and `lib/codegen/meta/constant_hash.rs`.
|
||||||
pub fn simple_hash(s: &str) -> usize {
|
pub fn simple_hash(s: &str) -> usize {
|
||||||
let mut h: u32 = 5381;
|
let mut h: u32 = 5381;
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
|
|||||||
Reference in New Issue
Block a user