Remove registers from cranelift-codegen-meta

This commit is contained in:
bjorn3
2021-06-21 12:57:37 +02:00
parent 18bd27e90b
commit 3e4167ba95
9 changed files with 6 additions and 573 deletions

View File

@@ -1,18 +1,12 @@
use crate::cdsl::regs::IsaRegs;
use crate::cdsl::settings::SettingGroup;
pub(crate) struct TargetIsa {
pub name: &'static str,
pub settings: SettingGroup,
pub regs: IsaRegs,
}
impl TargetIsa {
pub fn new(name: &'static str, settings: SettingGroup, regs: IsaRegs) -> Self {
Self {
name,
settings,
regs,
}
pub fn new(name: &'static str, settings: SettingGroup) -> Self {
Self { name, settings }
}
}

View File

@@ -7,7 +7,6 @@ pub mod formats;
pub mod instructions;
pub mod isa;
pub mod operands;
pub mod regs;
pub mod settings;
pub mod type_inference;
pub mod types;

View File

@@ -1,332 +0,0 @@
use cranelift_codegen_shared::constants;
use cranelift_entity::{entity_impl, EntityRef, PrimaryMap};
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) struct RegBankIndex(u32);
entity_impl!(RegBankIndex);
pub(crate) struct RegBank {
pub name: &'static str,
pub first_unit: u8,
pub units: u8,
pub names: Vec<&'static str>,
pub prefix: &'static str,
pub pressure_tracking: bool,
pub pinned_reg: Option<u16>,
pub toprcs: Vec<RegClassIndex>,
pub classes: Vec<RegClassIndex>,
}
impl RegBank {
pub fn new(
name: &'static str,
first_unit: u8,
units: u8,
names: Vec<&'static str>,
prefix: &'static str,
pressure_tracking: bool,
pinned_reg: Option<u16>,
) -> Self {
RegBank {
name,
first_unit,
units,
names,
prefix,
pressure_tracking,
pinned_reg,
toprcs: Vec::new(),
classes: Vec::new(),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub(crate) struct RegClassIndex(u32);
entity_impl!(RegClassIndex);
pub(crate) struct RegClass {
pub name: &'static str,
pub index: RegClassIndex,
pub width: u8,
pub bank: RegBankIndex,
pub toprc: RegClassIndex,
pub count: u8,
pub start: u8,
pub subclasses: Vec<RegClassIndex>,
}
impl RegClass {
pub fn new(
name: &'static str,
index: RegClassIndex,
width: u8,
bank: RegBankIndex,
toprc: RegClassIndex,
count: u8,
start: u8,
) -> Self {
Self {
name,
index,
width,
bank,
toprc,
count,
start,
subclasses: Vec::new(),
}
}
/// Compute a bit-mask of subclasses, including self.
pub fn subclass_mask(&self) -> u64 {
let mut m = 1 << self.index.index();
for rc in self.subclasses.iter() {
m |= 1 << rc.index();
}
m
}
/// Compute a bit-mask of the register units allocated by this register class.
pub fn mask(&self, bank_first_unit: u8) -> Vec<u32> {
let mut u = (self.start + bank_first_unit) as usize;
let mut out_mask = vec![0, 0, 0];
for _ in 0..self.count {
out_mask[u / 32] |= 1 << (u % 32);
u += self.width as usize;
}
out_mask
}
}
pub(crate) enum RegClassProto {
TopLevel(RegBankIndex),
}
pub(crate) struct RegClassBuilder {
pub name: &'static str,
pub width: u8,
pub count: u8,
pub start: u8,
pub proto: RegClassProto,
}
impl RegClassBuilder {
pub fn new_toplevel(name: &'static str, bank: RegBankIndex) -> Self {
Self {
name,
width: 1,
count: 0,
start: 0,
proto: RegClassProto::TopLevel(bank),
}
}
pub fn count(mut self, count: u8) -> Self {
self.count = count;
self
}
pub fn width(mut self, width: u8) -> Self {
match self.proto {
RegClassProto::TopLevel(_) => self.width = width,
}
self
}
}
pub(crate) struct RegBankBuilder {
pub name: &'static str,
pub units: u8,
pub names: Vec<&'static str>,
pub prefix: &'static str,
pub pressure_tracking: Option<bool>,
pub pinned_reg: Option<u16>,
}
impl RegBankBuilder {
pub fn new(name: &'static str, prefix: &'static str) -> Self {
Self {
name,
units: 0,
names: vec![],
prefix,
pressure_tracking: None,
pinned_reg: None,
}
}
pub fn units(mut self, units: u8) -> Self {
self.units = units;
self
}
pub fn names(mut self, names: Vec<&'static str>) -> Self {
self.names = names;
self
}
pub fn track_pressure(mut self, track: bool) -> Self {
self.pressure_tracking = Some(track);
self
}
}
pub(crate) struct IsaRegsBuilder {
pub banks: PrimaryMap<RegBankIndex, RegBank>,
pub classes: PrimaryMap<RegClassIndex, RegClass>,
}
impl IsaRegsBuilder {
pub fn new() -> Self {
Self {
banks: PrimaryMap::new(),
classes: PrimaryMap::new(),
}
}
pub fn add_bank(&mut self, builder: RegBankBuilder) -> RegBankIndex {
let first_unit = if self.banks.is_empty() {
0
} else {
let last = &self.banks.last().unwrap();
let first_available_unit = (last.first_unit + last.units) as i8;
let units = builder.units;
let align = if units.is_power_of_two() {
units
} else {
units.next_power_of_two()
} as i8;
(first_available_unit + align - 1) & -align
} as u8;
self.banks.push(RegBank::new(
builder.name,
first_unit,
builder.units,
builder.names,
builder.prefix,
builder
.pressure_tracking
.expect("Pressure tracking must be explicitly set"),
builder.pinned_reg,
))
}
pub fn add_class(&mut self, builder: RegClassBuilder) -> RegClassIndex {
let class_index = self.classes.next_key();
// Finish delayed construction of RegClass.
let (bank, toprc, start, width) = match builder.proto {
RegClassProto::TopLevel(bank_index) => {
self.banks
.get_mut(bank_index)
.unwrap()
.toprcs
.push(class_index);
(bank_index, class_index, builder.start, builder.width)
}
};
let reg_bank_units = self.banks.get(bank).unwrap().units;
assert!(start < reg_bank_units);
let count = if builder.count != 0 {
builder.count
} else {
reg_bank_units / width
};
let reg_class = RegClass::new(builder.name, class_index, width, bank, toprc, count, start);
self.classes.push(reg_class);
let reg_bank = self.banks.get_mut(bank).unwrap();
reg_bank.classes.push(class_index);
class_index
}
/// Checks that the set of register classes satisfies:
///
/// 1. Closed under intersection: The intersection of any two register
/// classes in the set is either empty or identical to a member of the
/// set.
/// 2. There are no identical classes under different names.
/// 3. Classes are sorted topologically such that all subclasses have a
/// higher index that the superclass.
pub fn build(self) -> IsaRegs {
for reg_bank in self.banks.values() {
for i1 in reg_bank.classes.iter() {
for i2 in reg_bank.classes.iter() {
if i1 >= i2 {
continue;
}
let rc1 = self.classes.get(*i1).unwrap();
let rc2 = self.classes.get(*i2).unwrap();
let rc1_mask = rc1.mask(0);
let rc2_mask = rc2.mask(0);
assert!(
rc1.width != rc2.width || rc1_mask != rc2_mask,
"no duplicates"
);
if rc1.width != rc2.width {
continue;
}
let mut intersect = Vec::new();
for (a, b) in rc1_mask.iter().zip(rc2_mask.iter()) {
intersect.push(a & b);
}
if intersect == vec![0; intersect.len()] {
continue;
}
// Classes must be topologically ordered, so the intersection can't be the
// superclass.
assert!(intersect != rc1_mask);
// If the intersection is the second one, then it must be a subclass.
if intersect == rc2_mask {
assert!(self
.classes
.get(*i1)
.unwrap()
.subclasses
.iter()
.any(|x| *x == *i2));
}
}
}
}
assert!(
self.classes.len() <= constants::MAX_NUM_REG_CLASSES,
"Too many register classes"
);
let num_toplevel = self
.classes
.values()
.filter(|x| x.toprc == x.index && self.banks.get(x.bank).unwrap().pressure_tracking)
.count();
assert!(
num_toplevel <= constants::MAX_TRACKED_TOP_RCS,
"Too many top-level register classes"
);
IsaRegs::new(self.banks, self.classes)
}
}
pub(crate) struct IsaRegs {
pub banks: PrimaryMap<RegBankIndex, RegBank>,
pub classes: PrimaryMap<RegClassIndex, RegClass>,
}
impl IsaRegs {
fn new(
banks: PrimaryMap<RegBankIndex, RegBank>,
classes: PrimaryMap<RegClassIndex, RegClass>,
) -> Self {
Self { banks, classes }
}
}

View File

@@ -1,148 +0,0 @@
//! Generate the ISA-specific registers.
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{RegBank, RegClass};
use crate::error;
use crate::srcgen::Formatter;
use cranelift_entity::EntityRef;
fn gen_regbank(fmt: &mut Formatter, reg_bank: &RegBank) {
let names = if !reg_bank.names.is_empty() {
format!(r#""{}""#, reg_bank.names.join(r#"", ""#))
} else {
"".to_string()
};
fmtln!(fmt, "RegBank {");
fmt.indent(|fmt| {
fmtln!(fmt, r#"name: "{}","#, reg_bank.name);
fmtln!(fmt, "first_unit: {},", reg_bank.first_unit);
fmtln!(fmt, "units: {},", reg_bank.units);
fmtln!(fmt, "names: &[{}],", names);
fmtln!(fmt, r#"prefix: "{}","#, reg_bank.prefix);
fmtln!(fmt, "first_toprc: {},", reg_bank.toprcs[0].index());
fmtln!(fmt, "num_toprcs: {},", reg_bank.toprcs.len());
fmtln!(
fmt,
"pressure_tracking: {},",
if reg_bank.pressure_tracking {
"true"
} else {
"false"
}
);
});
fmtln!(fmt, "},");
}
fn gen_regclass(isa: &TargetIsa, reg_class: &RegClass, fmt: &mut Formatter) {
let reg_bank = isa.regs.banks.get(reg_class.bank).unwrap();
let mask: Vec<String> = reg_class
.mask(reg_bank.first_unit)
.iter()
.map(|x| format!("0x{:08x}", x))
.collect();
let mask = mask.join(", ");
fmtln!(
fmt,
"pub static {}_DATA: RegClassData = RegClassData {{",
reg_class.name
);
fmt.indent(|fmt| {
fmtln!(fmt, r#"name: "{}","#, reg_class.name);
fmtln!(fmt, "index: {},", reg_class.index.index());
fmtln!(fmt, "width: {},", reg_class.width);
fmtln!(fmt, "bank: {},", reg_class.bank.index());
fmtln!(fmt, "toprc: {},", reg_class.toprc.index());
fmtln!(fmt, "first: {},", reg_bank.first_unit + reg_class.start);
fmtln!(fmt, "subclasses: {:#x},", reg_class.subclass_mask());
fmtln!(fmt, "mask: [{}],", mask);
fmtln!(
fmt,
"pinned_reg: {:?},",
reg_bank
.pinned_reg
.map(|index| index + reg_bank.first_unit as u16 + reg_class.start as u16)
);
fmtln!(fmt, "info: &INFO,");
});
fmtln!(fmt, "};");
fmtln!(fmt, "#[allow(dead_code)]");
fmtln!(
fmt,
"pub static {}: RegClass = &{}_DATA;",
reg_class.name,
reg_class.name
);
}
fn gen_regbank_units(reg_bank: &RegBank, fmt: &mut Formatter) {
for unit in 0..reg_bank.units {
let v = unit + reg_bank.first_unit;
if (unit as usize) < reg_bank.names.len() {
fmtln!(fmt, "{} = {},", reg_bank.names[unit as usize], v);
continue;
}
fmtln!(fmt, "{}{} = {},", reg_bank.prefix, unit, v);
}
}
fn gen_isa(isa: &TargetIsa, fmt: &mut Formatter) {
// Emit RegInfo.
fmtln!(fmt, "pub static INFO: RegInfo = RegInfo {");
fmt.indent(|fmt| {
fmtln!(fmt, "banks: &[");
// Bank descriptors.
fmt.indent(|fmt| {
for reg_bank in isa.regs.banks.values() {
gen_regbank(fmt, &reg_bank);
}
});
fmtln!(fmt, "],");
// References to register classes.
fmtln!(fmt, "classes: &[");
fmt.indent(|fmt| {
for reg_class in isa.regs.classes.values() {
fmtln!(fmt, "&{}_DATA,", reg_class.name);
}
});
fmtln!(fmt, "],");
});
fmtln!(fmt, "};");
// Register class descriptors.
for rc in isa.regs.classes.values() {
gen_regclass(&isa, rc, fmt);
}
// Emit constants for all the register units.
fmtln!(fmt, "#[allow(dead_code, non_camel_case_types)]");
fmtln!(fmt, "#[derive(Clone, Copy)]");
fmtln!(fmt, "pub enum RU {");
fmt.indent(|fmt| {
for reg_bank in isa.regs.banks.values() {
gen_regbank_units(reg_bank, fmt);
}
});
fmtln!(fmt, "}");
// Emit Into conversion for the RU class.
fmtln!(fmt, "impl Into<RegUnit> for RU {");
fmt.indent(|fmt| {
fmtln!(fmt, "fn into(self) -> RegUnit {");
fmt.indent(|fmt| {
fmtln!(fmt, "self as RegUnit");
});
fmtln!(fmt, "}");
});
fmtln!(fmt, "}");
}
pub(crate) fn generate(isa: &TargetIsa, filename: &str, out_dir: &str) -> Result<(), error::Error> {
let mut fmt = Formatter::new();
gen_isa(&isa, &mut fmt);
fmt.update_file(filename, out_dir)?;
Ok(())
}

View File

@@ -1,5 +1,4 @@
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
@@ -9,46 +8,8 @@ fn define_settings(_shared: &SettingGroup) -> SettingGroup {
setting.build()
}
fn define_regs() -> IsaRegs {
let mut regs = IsaRegsBuilder::new();
let builder = RegBankBuilder::new("FloatRegs", "s")
.units(64)
.track_pressure(true);
let float_regs = regs.add_bank(builder);
let builder = RegBankBuilder::new("IntRegs", "r")
.units(16)
.track_pressure(true);
let int_regs = regs.add_bank(builder);
let builder = RegBankBuilder::new("FlagRegs", "")
.units(1)
.names(vec!["nzcv"])
.track_pressure(false);
let flag_reg = regs.add_bank(builder);
let builder = RegClassBuilder::new_toplevel("S", float_regs).count(32);
regs.add_class(builder);
let builder = RegClassBuilder::new_toplevel("D", float_regs).width(2);
regs.add_class(builder);
let builder = RegClassBuilder::new_toplevel("Q", float_regs).width(4);
regs.add_class(builder);
let builder = RegClassBuilder::new_toplevel("GPR", int_regs);
regs.add_class(builder);
let builder = RegClassBuilder::new_toplevel("FLAG", flag_reg);
regs.add_class(builder);
regs.build()
}
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(&shared_defs.settings);
let regs = define_regs();
TargetIsa::new("arm32", settings, regs)
TargetIsa::new("arm32", settings)
}

View File

@@ -1,5 +1,4 @@
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::{IsaRegs, IsaRegsBuilder, RegBankBuilder, RegClassBuilder};
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
@@ -12,42 +11,8 @@ fn define_settings(_shared: &SettingGroup) -> SettingGroup {
setting.build()
}
fn define_registers() -> IsaRegs {
let mut regs = IsaRegsBuilder::new();
// The `x31` regunit serves as the stack pointer / zero register depending on context. We
// reserve it and don't model the difference.
let builder = RegBankBuilder::new("IntRegs", "x")
.units(32)
.track_pressure(true);
let int_regs = regs.add_bank(builder);
let builder = RegBankBuilder::new("FloatRegs", "v")
.units(32)
.track_pressure(true);
let float_regs = regs.add_bank(builder);
let builder = RegBankBuilder::new("FlagRegs", "")
.units(1)
.names(vec!["nzcv"])
.track_pressure(false);
let flag_reg = regs.add_bank(builder);
let builder = RegClassBuilder::new_toplevel("GPR", int_regs);
regs.add_class(builder);
let builder = RegClassBuilder::new_toplevel("FPR", float_regs);
regs.add_class(builder);
let builder = RegClassBuilder::new_toplevel("FLAG", flag_reg);
regs.add_class(builder);
regs.build()
}
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(&shared_defs.settings);
let regs = define_registers();
TargetIsa::new("arm64", settings, regs)
TargetIsa::new("arm64", settings)
}

View File

@@ -1,5 +1,4 @@
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::IsaRegsBuilder;
use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder};
use crate::shared::Definitions as SharedDefinitions;
@@ -43,7 +42,6 @@ fn define_settings(_shared: &SettingGroup) -> SettingGroup {
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = define_settings(&shared_defs.settings);
let regs = IsaRegsBuilder::new().build();
TargetIsa::new("s390x", settings, regs)
TargetIsa::new("s390x", settings)
}

View File

@@ -1,5 +1,4 @@
use crate::cdsl::isa::TargetIsa;
use crate::cdsl::regs::IsaRegsBuilder;
use crate::shared::Definitions as SharedDefinitions;
@@ -8,5 +7,5 @@ pub(crate) mod settings;
pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa {
let settings = settings::define(&shared_defs.settings);
TargetIsa::new("x86", settings, IsaRegsBuilder::new().build())
TargetIsa::new("x86", settings)
}

View File

@@ -8,7 +8,6 @@ pub mod error;
pub mod isa;
mod gen_inst;
mod gen_registers;
mod gen_settings;
mod gen_types;
@@ -55,8 +54,6 @@ pub fn generate(
)?;
for isa in target_isas {
gen_registers::generate(&isa, &format!("registers-{}.rs", isa.name), &out_dir)?;
gen_settings::generate(
&isa.settings,
gen_settings::ParentGroup::Shared,