diff --git a/lib/codegen/meta/src/cdsl/isa.rs b/lib/codegen/meta/src/cdsl/isa.rs index 4a6a819683..d1855176c9 100644 --- a/lib/codegen/meta/src/cdsl/isa.rs +++ b/lib/codegen/meta/src/cdsl/isa.rs @@ -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 } } diff --git a/lib/codegen/meta/src/cdsl/regs.rs b/lib/codegen/meta/src/cdsl/regs.rs index bc40ffaf69..4e8a34001b 100644 --- a/lib/codegen/meta/src/cdsl/regs.rs +++ b/lib/codegen/meta/src/cdsl/regs.rs @@ -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 } } diff --git a/lib/codegen/meta/src/isa/arm32/mod.rs b/lib/codegen/meta/src/isa/arm32/mod.rs index ce33422276..e0e47c2e2e 100644 --- a/lib/codegen/meta/src/isa/arm32/mod.rs +++ b/lib/codegen/meta/src/isa/arm32/mod.rs @@ -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() } diff --git a/lib/codegen/meta/src/isa/arm64/mod.rs b/lib/codegen/meta/src/isa/arm64/mod.rs index 8e13d28321..2435f3676e 100644 --- a/lib/codegen/meta/src/isa/arm64/mod.rs +++ b/lib/codegen/meta/src/isa/arm64/mod.rs @@ -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() } diff --git a/lib/codegen/meta/src/isa/mod.rs b/lib/codegen/meta/src/isa/mod.rs index ffb13fb151..18f75c42e5 100644 --- a/lib/codegen/meta/src/isa/mod.rs +++ b/lib/codegen/meta/src/isa/mod.rs @@ -62,14 +62,10 @@ impl fmt::Display for Isa { } pub fn define_all() -> Vec { - let isas = vec![ + vec![ riscv::define(), arm32::define(), arm64::define(), x86::define(), - ]; - for isa in isas.iter() { - isa.check(); - } - isas + ] } diff --git a/lib/codegen/meta/src/isa/riscv/mod.rs b/lib/codegen/meta/src/isa/riscv/mod.rs index 315ee42233..67f504c0f8 100644 --- a/lib/codegen/meta/src/isa/riscv/mod.rs +++ b/lib/codegen/meta/src/isa/riscv/mod.rs @@ -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() } diff --git a/lib/codegen/meta/src/isa/x86/mod.rs b/lib/codegen/meta/src/isa/x86/mod.rs index 43fd4ed67d..7970ea06db 100644 --- a/lib/codegen/meta/src/isa/x86/mod.rs +++ b/lib/codegen/meta/src/isa/x86/mod.rs @@ -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() }