xref: /wasmtime-44.0.1/winch/codegen/src/regset.rs (revision d36d4708)
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