[build] Introduce a TargetIsaBuilder to better encapsulate the TargetIsa;
It was the caller's responsibility to call TargetIsa::check() before; now one can't manipulate a TargetIsa without calling the TargetIsaBuilder::finish() method, which is less error-prone and more in line with what's coming for other things we're going to generate in the meta crate. Also splits the construction of a RegClass in two parts: a prototype is made first when declaring the RegClass, and missing bits are filled in when adding it to the TargetIsa(Builder). This avoids an awkward passing of the isa to the RegClass ctor.
This commit is contained in:
committed by
Dan Gohman
parent
f896bfb946
commit
add4043bb5
@@ -1,7 +1,7 @@
|
||||
use cranelift_entity::PrimaryMap;
|
||||
|
||||
use super::regs::{
|
||||
RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex,
|
||||
RegBank, RegBankBuilder, RegBankIndex, RegClass, RegClassBuilder, RegClassIndex, RegClassProto,
|
||||
};
|
||||
|
||||
pub struct TargetIsa {
|
||||
@@ -18,12 +18,24 @@ impl TargetIsa {
|
||||
reg_classes: PrimaryMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TargetIsaBuilder {
|
||||
isa: TargetIsa,
|
||||
}
|
||||
|
||||
impl TargetIsaBuilder {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
isa: TargetIsa::new(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_reg_bank(&mut self, builder: RegBankBuilder) -> RegBankIndex {
|
||||
let first_unit = if self.reg_banks.len() == 0 {
|
||||
let first_unit = if self.isa.reg_banks.len() == 0 {
|
||||
0
|
||||
} else {
|
||||
let last = &self.reg_banks.last().unwrap();
|
||||
let last = &self.isa.reg_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() {
|
||||
@@ -34,7 +46,7 @@ impl TargetIsa {
|
||||
(first_available_unit + align - 1) & -align
|
||||
} as u8;
|
||||
|
||||
self.reg_banks.push(RegBank::new(
|
||||
self.isa.reg_banks.push(RegBank::new(
|
||||
builder.name,
|
||||
first_unit,
|
||||
builder.units,
|
||||
@@ -47,38 +59,51 @@ impl TargetIsa {
|
||||
}
|
||||
|
||||
pub fn add_reg_class(&mut self, builder: RegClassBuilder) -> RegClassIndex {
|
||||
let reg_bank_units = self.reg_banks.get(builder.bank).unwrap().units;
|
||||
let class_index = self.isa.reg_classes.next_key();
|
||||
|
||||
let start = builder.start;
|
||||
// Finish delayed construction of RegClass.
|
||||
let (bank, toprc, start, width) = match builder.proto {
|
||||
RegClassProto::TopLevel(bank_index) => {
|
||||
self.isa
|
||||
.reg_banks
|
||||
.get_mut(bank_index)
|
||||
.unwrap()
|
||||
.toprcs
|
||||
.push(class_index);
|
||||
(bank_index, class_index, builder.start, builder.width)
|
||||
}
|
||||
RegClassProto::SubClass(parent_class_index) => {
|
||||
assert!(builder.width == 0);
|
||||
let (bank, toprc, start, width) = {
|
||||
let parent = self.isa.reg_classes.get(parent_class_index).unwrap();
|
||||
(parent.bank, parent.toprc, parent.start, parent.width)
|
||||
};
|
||||
for reg_class in self.isa.reg_classes.values_mut() {
|
||||
if reg_class.toprc == toprc {
|
||||
reg_class.subclasses.push(class_index);
|
||||
}
|
||||
}
|
||||
let subclass_start = start + builder.start * width;
|
||||
(bank, toprc, subclass_start, width)
|
||||
}
|
||||
};
|
||||
|
||||
let reg_bank_units = self.isa.reg_banks.get(bank).unwrap().units;
|
||||
assert!(start < reg_bank_units);
|
||||
|
||||
let count = if builder.count != 0 {
|
||||
builder.count
|
||||
} else {
|
||||
reg_bank_units / builder.width
|
||||
reg_bank_units / width
|
||||
};
|
||||
|
||||
let reg_class_index = builder.index;
|
||||
assert!(
|
||||
self.reg_classes.next_key() == reg_class_index,
|
||||
"should have inserted RegClass where expected"
|
||||
);
|
||||
let reg_class = RegClass::new(builder.name, class_index, width, bank, toprc, count, start);
|
||||
self.isa.reg_classes.push(reg_class);
|
||||
|
||||
let reg_class = RegClass::new(
|
||||
builder.name,
|
||||
reg_class_index,
|
||||
builder.width,
|
||||
builder.bank,
|
||||
builder.toprc,
|
||||
count,
|
||||
start,
|
||||
);
|
||||
self.reg_classes.push(reg_class);
|
||||
let reg_bank = self.isa.reg_banks.get_mut(bank).unwrap();
|
||||
reg_bank.classes.push(class_index);
|
||||
|
||||
let reg_bank = self.reg_banks.get_mut(builder.bank).unwrap();
|
||||
reg_bank.classes.push(reg_class_index);
|
||||
|
||||
reg_class_index
|
||||
class_index
|
||||
}
|
||||
|
||||
/// Checks that the set of register classes satisfies:
|
||||
@@ -89,16 +114,16 @@ impl TargetIsa {
|
||||
/// 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 check(&self) {
|
||||
for reg_bank in self.reg_banks.values() {
|
||||
pub fn finish(self) -> TargetIsa {
|
||||
for reg_bank in self.isa.reg_banks.values() {
|
||||
for i1 in reg_bank.classes.iter() {
|
||||
for i2 in reg_bank.classes.iter() {
|
||||
if i1 >= i2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let rc1 = self.reg_classes.get(*i1).unwrap();
|
||||
let rc2 = self.reg_classes.get(*i2).unwrap();
|
||||
let rc1 = self.isa.reg_classes.get(*i1).unwrap();
|
||||
let rc2 = self.isa.reg_classes.get(*i2).unwrap();
|
||||
|
||||
let rc1_mask = rc1.mask(0);
|
||||
let rc2_mask = rc2.mask(0);
|
||||
@@ -126,7 +151,8 @@ impl TargetIsa {
|
||||
// If the intersection is the second one, then it must be a subclass.
|
||||
if intersect == rc2_mask {
|
||||
assert!(
|
||||
self.reg_classes
|
||||
self.isa
|
||||
.reg_classes
|
||||
.get(*i1)
|
||||
.unwrap()
|
||||
.subclasses
|
||||
@@ -138,5 +164,7 @@ impl TargetIsa {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.isa
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use cranelift_entity::EntityRef;
|
||||
|
||||
use super::isa::TargetIsa;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct RegBankIndex(u32);
|
||||
entity_impl!(RegBankIndex);
|
||||
@@ -97,71 +95,53 @@ impl RegClass {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RegClassProto {
|
||||
TopLevel(RegBankIndex),
|
||||
SubClass(RegClassIndex),
|
||||
}
|
||||
|
||||
pub struct RegClassBuilder {
|
||||
pub name: &'static str,
|
||||
pub index: RegClassIndex,
|
||||
pub width: u8,
|
||||
pub bank: RegBankIndex,
|
||||
pub toprc: RegClassIndex,
|
||||
pub count: u8,
|
||||
pub start: u8,
|
||||
pub proto: RegClassProto,
|
||||
}
|
||||
|
||||
impl RegClassBuilder {
|
||||
pub fn new_toplevel(isa: &mut TargetIsa, name: &'static str, bank: RegBankIndex) -> Self {
|
||||
let index = isa.reg_classes.next_key();
|
||||
|
||||
// Add it to the top-level register classes of the register bank.
|
||||
isa.reg_banks.get_mut(bank).unwrap().toprcs.push(index);
|
||||
|
||||
pub fn new_toplevel(name: &'static str, bank: RegBankIndex) -> Self {
|
||||
Self {
|
||||
name,
|
||||
index,
|
||||
width: 1,
|
||||
bank,
|
||||
toprc: index,
|
||||
count: 0,
|
||||
start: 0,
|
||||
proto: RegClassProto::TopLevel(bank),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subclass_of(
|
||||
isa: &mut TargetIsa,
|
||||
name: &'static str,
|
||||
parent_index: RegClassIndex,
|
||||
start: u8,
|
||||
stop: u8,
|
||||
) -> Self {
|
||||
assert!(stop >= start);
|
||||
|
||||
let index = isa.reg_classes.next_key();
|
||||
|
||||
let toprc = isa.reg_classes.get(parent_index).unwrap().toprc;
|
||||
for reg_class in isa.reg_classes.values_mut() {
|
||||
if reg_class.toprc == toprc {
|
||||
reg_class.subclasses.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
let parent = &isa.reg_classes.get(parent_index).unwrap();
|
||||
Self {
|
||||
name,
|
||||
width: 0,
|
||||
count: stop - start,
|
||||
width: parent.width,
|
||||
start: parent.start + start * parent.width,
|
||||
bank: parent.bank,
|
||||
toprc: parent.toprc,
|
||||
index,
|
||||
start: start,
|
||||
proto: RegClassProto::SubClass(parent_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(mut self, count: u8) -> Self {
|
||||
self.count = count;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn width(mut self, width: u8) -> Self {
|
||||
self.width = width;
|
||||
match self.proto {
|
||||
RegClassProto::TopLevel(_) => self.width = width,
|
||||
RegClassProto::SubClass(_) => panic!("Subclasses inherit their parent's width."),
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use isa;
|
||||
|
||||
pub fn define() -> isa::TargetIsa {
|
||||
let mut isa = isa::TargetIsa::new("arm32");
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("arm32");
|
||||
|
||||
let builder = RegBankBuilder::new("FloatRegs", "s")
|
||||
.units(64)
|
||||
@@ -20,20 +20,20 @@ pub fn define() -> isa::TargetIsa {
|
||||
.track_pressure(false);
|
||||
let flag_reg = isa.add_reg_bank(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "S", float_regs).count(32);
|
||||
let builder = RegClassBuilder::new_toplevel("S", float_regs).count(32);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "D", float_regs).width(2);
|
||||
let builder = RegClassBuilder::new_toplevel("D", float_regs).width(2);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "Q", float_regs).width(4);
|
||||
let builder = RegClassBuilder::new_toplevel("Q", float_regs).width(4);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("GPR", int_regs);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "FLAG", flag_reg);
|
||||
let builder = RegClassBuilder::new_toplevel("FLAG", flag_reg);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
isa
|
||||
isa.finish()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use isa;
|
||||
|
||||
pub fn define() -> isa::TargetIsa {
|
||||
let mut isa = isa::TargetIsa::new("arm64");
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("arm64");
|
||||
|
||||
// The `x31` regunit serves as the stack pointer / zero register depending on context. We
|
||||
// reserve it and don't model the difference.
|
||||
@@ -22,14 +22,14 @@ pub fn define() -> isa::TargetIsa {
|
||||
.track_pressure(false);
|
||||
let flag_reg = isa.add_reg_bank(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("GPR", int_regs);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "FPR", float_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("FPR", float_regs);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "FLAG", flag_reg);
|
||||
let builder = RegClassBuilder::new_toplevel("FLAG", flag_reg);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
isa
|
||||
isa.finish()
|
||||
}
|
||||
|
||||
@@ -62,14 +62,10 @@ impl fmt::Display for Isa {
|
||||
}
|
||||
|
||||
pub fn define_all() -> Vec<TargetIsa> {
|
||||
let isas = vec![
|
||||
vec![
|
||||
riscv::define(),
|
||||
arm32::define(),
|
||||
arm64::define(),
|
||||
x86::define(),
|
||||
];
|
||||
for isa in isas.iter() {
|
||||
isa.check();
|
||||
}
|
||||
isas
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use isa;
|
||||
|
||||
pub fn define() -> isa::TargetIsa {
|
||||
let mut isa = isa::TargetIsa::new("riscv");
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("riscv");
|
||||
|
||||
let builder = RegBankBuilder::new("IntRegs", "x")
|
||||
.units(32)
|
||||
@@ -14,11 +14,11 @@ pub fn define() -> isa::TargetIsa {
|
||||
.track_pressure(true);
|
||||
let float_regs = isa.add_reg_bank(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("GPR", int_regs);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "FPR", float_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("FPR", float_regs);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
isa
|
||||
isa.finish()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use cdsl::isa::{TargetIsa, TargetIsaBuilder};
|
||||
use cdsl::regs::{RegBankBuilder, RegClassBuilder};
|
||||
use isa;
|
||||
|
||||
pub fn define() -> isa::TargetIsa {
|
||||
let mut isa = isa::TargetIsa::new("x86");
|
||||
pub fn define() -> TargetIsa {
|
||||
let mut isa = TargetIsaBuilder::new("x86");
|
||||
|
||||
let builder = RegBankBuilder::new("IntRegs", "r")
|
||||
.units(16)
|
||||
@@ -21,23 +21,23 @@ pub fn define() -> isa::TargetIsa {
|
||||
.track_pressure(false);
|
||||
let flag_reg = isa.add_reg_bank(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "GPR", int_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("GPR", int_regs);
|
||||
let gpr = isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "FPR", float_regs);
|
||||
let builder = RegClassBuilder::new_toplevel("FPR", float_regs);
|
||||
let fpr = isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::new_toplevel(&mut isa, "FLAG", flag_reg);
|
||||
let builder = RegClassBuilder::new_toplevel("FLAG", flag_reg);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::subclass_of(&mut isa, "GPR8", gpr, 0, 8);
|
||||
let builder = RegClassBuilder::subclass_of("GPR8", gpr, 0, 8);
|
||||
let gpr8 = isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::subclass_of(&mut isa, "ABCD", gpr8, 0, 4);
|
||||
let builder = RegClassBuilder::subclass_of("ABCD", gpr8, 0, 4);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
let builder = RegClassBuilder::subclass_of(&mut isa, "FPR8", fpr, 0, 8);
|
||||
let builder = RegClassBuilder::subclass_of("FPR8", fpr, 0, 8);
|
||||
isa.add_reg_class(builder);
|
||||
|
||||
isa
|
||||
isa.finish()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user