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