1use crate::isa::reg::{Reg, RegClass};
2
3pub(crate) struct RegSet {
5 gpr: RegBitSet,
7 fpr: RegBitSet,
9}
10
11use std::ops::{Index, IndexMut};
12
13impl Index<RegClass> for RegSet {
14 type Output = RegBitSet;
15
16 fn index(&self, class: RegClass) -> &Self::Output {
17 match class {
18 RegClass::Int => &self.gpr,
19 RegClass::Float => &self.fpr,
20 c => unreachable!("Unexpected register class {:?}", c),
21 }
22 }
23}
24
25impl IndexMut<RegClass> for RegSet {
26 fn index_mut(&mut self, class: RegClass) -> &mut Self::Output {
27 match class {
28 RegClass::Int => &mut self.gpr,
29 RegClass::Float => &mut self.fpr,
30 c => unreachable!("Unexpected register class {:?}", c),
31 }
32 }
33}
34
35pub struct RegBitSet {
37 class: RegClass,
39 allocatable: u64,
41 non_allocatable: u64,
43 max: usize,
48}
49
50impl RegBitSet {
51 pub fn int(allocatable: u64, non_allocatable: u64, max: usize) -> Self {
53 debug_assert!(allocatable & non_allocatable == 0);
55 Self {
56 class: RegClass::Int,
57 allocatable,
58 non_allocatable,
59 max,
60 }
61 }
62
63 pub fn float(allocatable: u64, non_allocatable: u64, max: usize) -> Self {
65 debug_assert!(allocatable & non_allocatable == 0);
67 Self {
68 class: RegClass::Float,
69 allocatable,
70 non_allocatable,
71 max,
72 }
73 }
74}
75
76impl RegSet {
77 pub fn new(gpr: RegBitSet, fpr: RegBitSet) -> Self {
79 debug_assert!(gpr.class == RegClass::Int);
80 debug_assert!(fpr.class == RegClass::Float);
81
82 Self { gpr, fpr }
83 }
84
85 pub fn reg_for_class(&mut self, class: RegClass) -> Option<Reg> {
88 self.available(class).then(|| {
89 let bitset = &self[class];
90 let index = bitset.allocatable.trailing_zeros();
91 self.allocate(class, index.into());
92 Reg::from(class, index as usize)
93 })
94 }
95
96 pub fn reg(&mut self, reg: Reg) -> Option<Reg> {
98 let index = reg.hw_enc();
99 self.named_reg_available(reg).then(|| {
100 self.allocate(reg.class(), index.try_into().unwrap());
101 reg
102 })
103 }
104
105 pub fn free(&mut self, reg: Reg) {
108 let bitset = &self[reg.class()];
109 let index = reg.hw_enc();
110 assert!(index < bitset.max);
111 let index = u64::try_from(index).unwrap();
112 if !self.is_non_allocatable(reg.class(), index) {
113 self[reg.class()].allocatable |= 1 << index;
114 }
115 }
116
117 pub fn named_reg_available(&self, reg: Reg) -> bool {
119 let bitset = &self[reg.class()];
120 assert!(reg.hw_enc() < bitset.max);
121 let index = 1 << reg.hw_enc();
122
123 (!bitset.allocatable & index) == 0
124 || self.is_non_allocatable(reg.class(), reg.hw_enc().try_into().unwrap())
125 }
126
127 fn available(&self, class: RegClass) -> bool {
128 let bitset = &self[class];
129 bitset.allocatable != 0
130 }
131
132 fn allocate(&mut self, class: RegClass, index: u64) {
133 if !self.is_non_allocatable(class, index) {
134 self[class].allocatable &= !(1 << index);
135 }
136 }
137
138 fn is_non_allocatable(&self, class: RegClass, index: u64) -> bool {
139 let bitset = &self[class];
140 let non_allocatable = bitset.non_allocatable;
141 non_allocatable != 0 && !non_allocatable & (1 << index) == 0
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::{Reg, RegBitSet, RegClass, RegSet};
148
149 const UNIVERSE: u64 = (1 << 16) - 1;
150 const MAX: usize = 16;
151
152 #[test]
153 fn test_any_gpr() {
154 let bitset = RegBitSet::int(UNIVERSE, !UNIVERSE, MAX);
155 let zero = RegBitSet::float(0, 0, MAX);
156 let mut set = RegSet::new(bitset, zero);
157 for _ in 0..16 {
158 let gpr = set.reg_for_class(RegClass::Int);
159 assert!(gpr.is_some())
160 }
161
162 assert!(!set.available(RegClass::Int));
163 assert!(set.reg_for_class(RegClass::Int).is_none())
164 }
165
166 #[test]
167 fn test_gpr() {
168 let non_allocatable: u64 = 1 << 5;
169 let all = UNIVERSE & !non_allocatable;
170 let non_alloc = Reg::int(5);
171 let alloc = Reg::int(2);
172 let bitset = RegBitSet::int(all, non_allocatable, MAX);
173 let zero = RegBitSet::float(0, 0, MAX);
174 let mut set = RegSet::new(bitset, zero);
175 assert!(set.reg(non_alloc).is_some());
178 assert!(set.reg(non_alloc).is_some());
179 assert!(set.reg(alloc).is_some());
182 assert!(set.reg(alloc).is_none());
183 }
184
185 #[test]
186 fn test_free_reg() {
187 let set = RegBitSet::int(UNIVERSE, !UNIVERSE, MAX);
188 let zero = RegBitSet::float(0, 0, MAX);
189 let mut set = RegSet::new(set, zero);
190 let gpr = set.reg_for_class(RegClass::Int).unwrap();
191 set.free(gpr);
192 assert!(set.reg(gpr).is_some());
193 }
194}