1 use crate::isa::reg::Reg; 2 3 /// A bit set to track regiter availability. 4 pub(crate) struct RegSet { 5 /// Bitset to track general purpose register availability. 6 gpr: u32, 7 /// Bitset to track floating-point register availability. 8 _fpr: u32, 9 } 10 11 impl RegSet { 12 /// Create a new register set. 13 pub fn new(gpr: u32, fpr: u32) -> Self { 14 Self { gpr, _fpr: fpr } 15 } 16 17 /// Request a general purpose register. 18 pub fn any_gpr(&mut self) -> Option<Reg> { 19 self.gpr_available().then(|| { 20 let index = self.gpr.trailing_zeros(); 21 self.allocate(index); 22 Reg::int(index as usize) 23 }) 24 } 25 26 /// Request a specific general purpose register. 27 pub fn gpr(&mut self, reg: Reg) -> Option<Reg> { 28 let index = reg.hw_enc(); 29 self.named_gpr_available(index as u32).then(|| { 30 self.allocate(index as u32); 31 Reg::int(index as usize) 32 }) 33 } 34 35 /// Free the given general purpose register. 36 pub fn free_gpr(&mut self, reg: Reg) { 37 let index = reg.hw_enc() as u32; 38 self.gpr |= 1 << index; 39 } 40 41 fn named_gpr_available(&self, index: u32) -> bool { 42 let index = 1 << index; 43 (!self.gpr & index) == 0 44 } 45 46 fn gpr_available(&self) -> bool { 47 self.gpr != 0 48 } 49 50 fn allocate(&mut self, index: u32) { 51 self.gpr &= !(1 << index); 52 } 53 } 54 55 #[cfg(test)] 56 mod tests { 57 use super::{Reg, RegSet}; 58 59 const UNIVERSE: u32 = (1 << 16) - 1; 60 61 #[test] 62 fn test_any_gpr() { 63 let mut set = RegSet::new(UNIVERSE, 0); 64 for _ in 0..16 { 65 let gpr = set.any_gpr(); 66 assert!(gpr.is_some()) 67 } 68 69 assert!(!set.gpr_available()); 70 assert!(set.any_gpr().is_none()) 71 } 72 73 #[test] 74 fn test_gpr() { 75 let all = UNIVERSE & !(1 << 5); 76 let target = Reg::int(5); 77 let mut set = RegSet::new(all, 0); 78 assert!(set.gpr(target).is_none()); 79 } 80 81 #[test] 82 fn test_free_gpr() { 83 let mut set = RegSet::new(UNIVERSE, 0); 84 let gpr = set.any_gpr().unwrap(); 85 set.free_gpr(gpr); 86 assert!(set.gpr(gpr).is_some()); 87 } 88 } 89