12da108dfSSaúl Cabrera use crate::isa::reg::{Reg, RegClass}; 2835abbcdSSaúl Cabrera 3*d36d4708SEdoardo Vacchi /// A bit set to track register availability. 4835abbcdSSaúl Cabrera pub(crate) struct RegSet { 5835abbcdSSaúl Cabrera /// Bitset to track general purpose register availability. 64b288ba8SSaúl Cabrera gpr: RegBitSet, 7835abbcdSSaúl Cabrera /// Bitset to track floating-point register availability. 84b288ba8SSaúl Cabrera fpr: RegBitSet, 914b39bc2SSaúl Cabrera } 1014b39bc2SSaúl Cabrera 1114b39bc2SSaúl Cabrera use std::ops::{Index, IndexMut}; 1214b39bc2SSaúl Cabrera 1314b39bc2SSaúl Cabrera impl Index<RegClass> for RegSet { 144b288ba8SSaúl Cabrera type Output = RegBitSet; 1514b39bc2SSaúl Cabrera index(&self, class: RegClass) -> &Self::Output1614b39bc2SSaúl Cabrera fn index(&self, class: RegClass) -> &Self::Output { 1714b39bc2SSaúl Cabrera match class { 1814b39bc2SSaúl Cabrera RegClass::Int => &self.gpr, 1914b39bc2SSaúl Cabrera RegClass::Float => &self.fpr, 2014b39bc2SSaúl Cabrera c => unreachable!("Unexpected register class {:?}", c), 2114b39bc2SSaúl Cabrera } 2214b39bc2SSaúl Cabrera } 2314b39bc2SSaúl Cabrera } 2414b39bc2SSaúl Cabrera 2514b39bc2SSaúl Cabrera impl IndexMut<RegClass> for RegSet { index_mut(&mut self, class: RegClass) -> &mut Self::Output2614b39bc2SSaúl Cabrera fn index_mut(&mut self, class: RegClass) -> &mut Self::Output { 2714b39bc2SSaúl Cabrera match class { 2814b39bc2SSaúl Cabrera RegClass::Int => &mut self.gpr, 2914b39bc2SSaúl Cabrera RegClass::Float => &mut self.fpr, 3014b39bc2SSaúl Cabrera c => unreachable!("Unexpected register class {:?}", c), 3114b39bc2SSaúl Cabrera } 3214b39bc2SSaúl Cabrera } 33835abbcdSSaúl Cabrera } 34835abbcdSSaúl Cabrera 354b288ba8SSaúl Cabrera /// Bitset for a particular register class. 364b288ba8SSaúl Cabrera pub struct RegBitSet { 374b288ba8SSaúl Cabrera /// The register class. 384b288ba8SSaúl Cabrera class: RegClass, 394b288ba8SSaúl Cabrera /// The set of allocatable 404b288ba8SSaúl Cabrera allocatable: u64, 414b288ba8SSaúl Cabrera /// The set of non-alloctable registers. 424b288ba8SSaúl Cabrera non_allocatable: u64, 434b288ba8SSaúl Cabrera /// The max number of registers. 444b288ba8SSaúl Cabrera /// Invariant: 454b288ba8SSaúl Cabrera /// When allocating or freeing a register the encoding (index) of the 464b288ba8SSaúl Cabrera /// register must be less than the max property. 474b288ba8SSaúl Cabrera max: usize, 484b288ba8SSaúl Cabrera } 494b288ba8SSaúl Cabrera 504b288ba8SSaúl Cabrera impl RegBitSet { 514b288ba8SSaúl Cabrera /// Creates an integer register class bitset. int(allocatable: u64, non_allocatable: u64, max: usize) -> Self524b288ba8SSaúl Cabrera pub fn int(allocatable: u64, non_allocatable: u64, max: usize) -> Self { 534b288ba8SSaúl Cabrera // Assert that one set is the complement of the other. 544b288ba8SSaúl Cabrera debug_assert!(allocatable & non_allocatable == 0); 554b288ba8SSaúl Cabrera Self { 564b288ba8SSaúl Cabrera class: RegClass::Int, 574b288ba8SSaúl Cabrera allocatable, 584b288ba8SSaúl Cabrera non_allocatable, 594b288ba8SSaúl Cabrera max, 604b288ba8SSaúl Cabrera } 614b288ba8SSaúl Cabrera } 624b288ba8SSaúl Cabrera 634b288ba8SSaúl Cabrera /// Creates a float register class bitset. float(allocatable: u64, non_allocatable: u64, max: usize) -> Self644b288ba8SSaúl Cabrera pub fn float(allocatable: u64, non_allocatable: u64, max: usize) -> Self { 654b288ba8SSaúl Cabrera // Assert that one set is the complement of the other. 664b288ba8SSaúl Cabrera debug_assert!(allocatable & non_allocatable == 0); 674b288ba8SSaúl Cabrera Self { 684b288ba8SSaúl Cabrera class: RegClass::Float, 694b288ba8SSaúl Cabrera allocatable, 704b288ba8SSaúl Cabrera non_allocatable, 714b288ba8SSaúl Cabrera max, 724b288ba8SSaúl Cabrera } 734b288ba8SSaúl Cabrera } 744b288ba8SSaúl Cabrera } 754b288ba8SSaúl Cabrera 76835abbcdSSaúl Cabrera impl RegSet { 77835abbcdSSaúl Cabrera /// Create a new register set. new(gpr: RegBitSet, fpr: RegBitSet) -> Self784b288ba8SSaúl Cabrera pub fn new(gpr: RegBitSet, fpr: RegBitSet) -> Self { 794b288ba8SSaúl Cabrera debug_assert!(gpr.class == RegClass::Int); 804b288ba8SSaúl Cabrera debug_assert!(fpr.class == RegClass::Float); 814b288ba8SSaúl Cabrera 8214b39bc2SSaúl Cabrera Self { gpr, fpr } 83835abbcdSSaúl Cabrera } 84835abbcdSSaúl Cabrera 8514b39bc2SSaúl Cabrera /// Allocate the next available register of the given class, 8614b39bc2SSaúl Cabrera /// returning `None` if there are no more registers available. reg_for_class(&mut self, class: RegClass) -> Option<Reg>8714b39bc2SSaúl Cabrera pub fn reg_for_class(&mut self, class: RegClass) -> Option<Reg> { 8814b39bc2SSaúl Cabrera self.available(class).then(|| { 894b288ba8SSaúl Cabrera let bitset = &self[class]; 904b288ba8SSaúl Cabrera let index = bitset.allocatable.trailing_zeros(); 914b288ba8SSaúl Cabrera self.allocate(class, index.into()); 9214b39bc2SSaúl Cabrera Reg::from(class, index as usize) 93835abbcdSSaúl Cabrera }) 94835abbcdSSaúl Cabrera } 95835abbcdSSaúl Cabrera 9614b39bc2SSaúl Cabrera /// Request a specific register. reg(&mut self, reg: Reg) -> Option<Reg>9714b39bc2SSaúl Cabrera pub fn reg(&mut self, reg: Reg) -> Option<Reg> { 98835abbcdSSaúl Cabrera let index = reg.hw_enc(); 9914b39bc2SSaúl Cabrera self.named_reg_available(reg).then(|| { 1004b288ba8SSaúl Cabrera self.allocate(reg.class(), index.try_into().unwrap()); 10114b39bc2SSaúl Cabrera reg 102835abbcdSSaúl Cabrera }) 103835abbcdSSaúl Cabrera } 104835abbcdSSaúl Cabrera 10514b39bc2SSaúl Cabrera /// Marks the specified register as available, utilizing the 10614b39bc2SSaúl Cabrera /// register class to determine the bitset that requires updating. free(&mut self, reg: Reg)10714b39bc2SSaúl Cabrera pub fn free(&mut self, reg: Reg) { 1084b288ba8SSaúl Cabrera let bitset = &self[reg.class()]; 1094b288ba8SSaúl Cabrera let index = reg.hw_enc(); 1104b288ba8SSaúl Cabrera assert!(index < bitset.max); 1114b288ba8SSaúl Cabrera let index = u64::try_from(index).unwrap(); 1124b288ba8SSaúl Cabrera if !self.is_non_allocatable(reg.class(), index) { 1134b288ba8SSaúl Cabrera self[reg.class()].allocatable |= 1 << index; 1144b288ba8SSaúl Cabrera } 115835abbcdSSaúl Cabrera } 116835abbcdSSaúl Cabrera 11714b39bc2SSaúl Cabrera /// Returns true if the specified register is allocatable. named_reg_available(&self, reg: Reg) -> bool11814b39bc2SSaúl Cabrera pub fn named_reg_available(&self, reg: Reg) -> bool { 1194b288ba8SSaúl Cabrera let bitset = &self[reg.class()]; 1204b288ba8SSaúl Cabrera assert!(reg.hw_enc() < bitset.max); 12114b39bc2SSaúl Cabrera let index = 1 << reg.hw_enc(); 1224b288ba8SSaúl Cabrera 1234b288ba8SSaúl Cabrera (!bitset.allocatable & index) == 0 1244b288ba8SSaúl Cabrera || self.is_non_allocatable(reg.class(), reg.hw_enc().try_into().unwrap()) 125835abbcdSSaúl Cabrera } 126835abbcdSSaúl Cabrera available(&self, class: RegClass) -> bool12714b39bc2SSaúl Cabrera fn available(&self, class: RegClass) -> bool { 1284b288ba8SSaúl Cabrera let bitset = &self[class]; 1294b288ba8SSaúl Cabrera bitset.allocatable != 0 130835abbcdSSaúl Cabrera } 131835abbcdSSaúl Cabrera allocate(&mut self, class: RegClass, index: u64)1324b288ba8SSaúl Cabrera fn allocate(&mut self, class: RegClass, index: u64) { 1334b288ba8SSaúl Cabrera if !self.is_non_allocatable(class, index) { 1344b288ba8SSaúl Cabrera self[class].allocatable &= !(1 << index); 1354b288ba8SSaúl Cabrera } 1364b288ba8SSaúl Cabrera } 1374b288ba8SSaúl Cabrera is_non_allocatable(&self, class: RegClass, index: u64) -> bool1384b288ba8SSaúl Cabrera fn is_non_allocatable(&self, class: RegClass, index: u64) -> bool { 1394b288ba8SSaúl Cabrera let bitset = &self[class]; 1404b288ba8SSaúl Cabrera let non_allocatable = bitset.non_allocatable; 1414b288ba8SSaúl Cabrera non_allocatable != 0 && !non_allocatable & (1 << index) == 0 142835abbcdSSaúl Cabrera } 143835abbcdSSaúl Cabrera } 144835abbcdSSaúl Cabrera 145835abbcdSSaúl Cabrera #[cfg(test)] 146835abbcdSSaúl Cabrera mod tests { 1474b288ba8SSaúl Cabrera use super::{Reg, RegBitSet, RegClass, RegSet}; 148835abbcdSSaúl Cabrera 1494b288ba8SSaúl Cabrera const UNIVERSE: u64 = (1 << 16) - 1; 1504b288ba8SSaúl Cabrera const MAX: usize = 16; 151835abbcdSSaúl Cabrera 152835abbcdSSaúl Cabrera #[test] test_any_gpr()153835abbcdSSaúl Cabrera fn test_any_gpr() { 1544b288ba8SSaúl Cabrera let bitset = RegBitSet::int(UNIVERSE, !UNIVERSE, MAX); 1554b288ba8SSaúl Cabrera let zero = RegBitSet::float(0, 0, MAX); 1564b288ba8SSaúl Cabrera let mut set = RegSet::new(bitset, zero); 157835abbcdSSaúl Cabrera for _ in 0..16 { 15814b39bc2SSaúl Cabrera let gpr = set.reg_for_class(RegClass::Int); 159835abbcdSSaúl Cabrera assert!(gpr.is_some()) 160835abbcdSSaúl Cabrera } 161835abbcdSSaúl Cabrera 16214b39bc2SSaúl Cabrera assert!(!set.available(RegClass::Int)); 16314b39bc2SSaúl Cabrera assert!(set.reg_for_class(RegClass::Int).is_none()) 164835abbcdSSaúl Cabrera } 165835abbcdSSaúl Cabrera 166835abbcdSSaúl Cabrera #[test] test_gpr()167835abbcdSSaúl Cabrera fn test_gpr() { 1684b288ba8SSaúl Cabrera let non_allocatable: u64 = 1 << 5; 1694b288ba8SSaúl Cabrera let all = UNIVERSE & !non_allocatable; 1704b288ba8SSaúl Cabrera let non_alloc = Reg::int(5); 1714b288ba8SSaúl Cabrera let alloc = Reg::int(2); 1724b288ba8SSaúl Cabrera let bitset = RegBitSet::int(all, non_allocatable, MAX); 1734b288ba8SSaúl Cabrera let zero = RegBitSet::float(0, 0, MAX); 1744b288ba8SSaúl Cabrera let mut set = RegSet::new(bitset, zero); 1754b288ba8SSaúl Cabrera // Requesting a non alloctable register returns the register 1764b288ba8SSaúl Cabrera // and doesn't allocate it. 1774b288ba8SSaúl Cabrera assert!(set.reg(non_alloc).is_some()); 1784b288ba8SSaúl Cabrera assert!(set.reg(non_alloc).is_some()); 1794b288ba8SSaúl Cabrera // Requesting an allocatable register twice returns none the 1804b288ba8SSaúl Cabrera // second time. 1814b288ba8SSaúl Cabrera assert!(set.reg(alloc).is_some()); 1824b288ba8SSaúl Cabrera assert!(set.reg(alloc).is_none()); 183835abbcdSSaúl Cabrera } 184835abbcdSSaúl Cabrera 185835abbcdSSaúl Cabrera #[test] test_free_reg()18614b39bc2SSaúl Cabrera fn test_free_reg() { 1874b288ba8SSaúl Cabrera let set = RegBitSet::int(UNIVERSE, !UNIVERSE, MAX); 1884b288ba8SSaúl Cabrera let zero = RegBitSet::float(0, 0, MAX); 1894b288ba8SSaúl Cabrera let mut set = RegSet::new(set, zero); 19014b39bc2SSaúl Cabrera let gpr = set.reg_for_class(RegClass::Int).unwrap(); 19114b39bc2SSaúl Cabrera set.free(gpr); 19214b39bc2SSaúl Cabrera assert!(set.reg(gpr).is_some()); 193835abbcdSSaúl Cabrera } 194835abbcdSSaúl Cabrera } 195