1use crate::{FxHashSet, PReg, PRegSet, RegClass};
2use alloc::vec;
3use alloc::vec::Vec;
4use core::{
5 fmt,
6 ops::{Index, IndexMut},
7};
8
9pub struct Lru {
11 pub data: Vec<LruNode>,
16 pub head: u8,
18 pub regclass: RegClass,
20}
21
22#[derive(Clone, Copy, Debug)]
23pub struct LruNode {
24 pub prev: u8,
26 pub next: u8,
28}
29
30impl Lru {
31 pub fn new(regclass: RegClass, regs: &[PReg]) -> Self {
32 let mut data = vec![
33 LruNode {
34 prev: u8::MAX,
35 next: u8::MAX
36 };
37 PReg::MAX + 1
38 ];
39 let no_of_regs = regs.len();
40 for i in 0..no_of_regs {
41 let (reg, prev_reg, next_reg) = (
42 regs[i],
43 regs[i.checked_sub(1).unwrap_or(no_of_regs - 1)],
44 regs[if i >= no_of_regs - 1 { 0 } else { i + 1 }],
45 );
46 data[reg.hw_enc()].prev = prev_reg.hw_enc() as u8;
47 data[reg.hw_enc()].next = next_reg.hw_enc() as u8;
48 }
49 Self {
50 head: if regs.is_empty() {
51 u8::MAX
52 } else {
53 regs[0].hw_enc() as u8
54 },
55 data,
56 regclass,
57 }
58 }
59
60 pub fn poke(&mut self, preg: PReg) {
62 trace!(
63 "Before poking: {:?} LRU. head: {:?}, Actual data: {:?}",
64 self.regclass,
65 self.head,
66 self.data
67 );
68 trace!("About to poke {:?} in {:?} LRU", preg, self.regclass);
69 let prev_newest = self.head;
70 let hw_enc = preg.hw_enc() as u8;
71 if hw_enc == prev_newest {
72 return;
73 }
74 if self.data[prev_newest as usize].prev != hw_enc {
75 self.remove(hw_enc as usize);
76 self.insert_before(hw_enc, self.head);
77 }
78 self.head = hw_enc;
79 trace!("Poked {:?} in {:?} LRU", preg, self.regclass);
80 if cfg!(debug_assertions) {
81 self.validate_lru();
82 }
83 }
84
85 pub fn pop(&mut self) -> PReg {
87 trace!(
88 "Before popping: {:?} LRU. head: {:?}, Actual data: {:?}",
89 self.regclass,
90 self.head,
91 self.data
92 );
93 trace!("Popping {:?} LRU", self.regclass);
94 if self.is_empty() {
95 panic!("LRU is empty");
96 }
97 let oldest = self.data[self.head as usize].prev;
98 trace!("Popped p{oldest} in {:?} LRU", self.regclass);
99 if cfg!(debug_assertions) {
100 self.validate_lru();
101 }
102 PReg::new(oldest as usize, self.regclass)
103 }
104
105 pub fn last(&self, from: PRegSet) -> Option<PReg> {
107 trace!("Getting the last preg from the LRU in set {from}");
108 self.last_satisfying(|preg| from.contains(preg))
109 }
110
111 pub fn last_satisfying<F: Fn(PReg) -> bool>(&self, f: F) -> Option<PReg> {
113 trace!("Getting the last preg from the LRU satisfying...");
114 if self.is_empty() {
115 panic!("LRU is empty");
116 }
117 let mut last = self.data[self.head as usize].prev;
118 let init_last = last;
119 loop {
120 let preg = PReg::new(last as usize, self.regclass);
121 if f(preg) {
122 return Some(preg);
123 }
124 last = self.data[last as usize].prev;
125 if last == init_last {
126 return None;
127 }
128 }
129 }
130
131 fn remove(&mut self, hw_enc: usize) {
133 trace!(
134 "Before removing: {:?} LRU. head: {:?}, Actual data: {:?}",
135 self.regclass,
136 self.head,
137 self.data
138 );
139 trace!("Removing p{hw_enc} from {:?} LRU", self.regclass);
140 let (iprev, inext) = (
141 self.data[hw_enc].prev as usize,
142 self.data[hw_enc].next as usize,
143 );
144 self.data[iprev].next = self.data[hw_enc].next;
145 self.data[inext].prev = self.data[hw_enc].prev;
146 self.data[hw_enc].prev = u8::MAX;
147 self.data[hw_enc].next = u8::MAX;
148 if hw_enc == self.head as usize {
149 if hw_enc == inext {
150 self.head = u8::MAX;
152 } else {
153 self.head = inext as u8;
154 }
155 }
156 trace!("Removed p{hw_enc} from {:?} LRU", self.regclass);
157 if cfg!(debug_assertions) {
158 self.validate_lru();
159 }
160 }
161
162 fn insert_before(&mut self, i: u8, j: u8) {
164 trace!(
165 "Before inserting: {:?} LRU. head: {:?}, Actual data: {:?}",
166 self.regclass,
167 self.head,
168 self.data
169 );
170 trace!("Inserting p{i} before {j} in {:?} LRU", self.regclass);
171 let prev = self.data[j as usize].prev;
172 self.data[prev as usize].next = i;
173 self.data[j as usize].prev = i;
174 self.data[i as usize] = LruNode { next: j, prev };
175 trace!("Done inserting p{i} before {j} in {:?} LRU", self.regclass);
176 if cfg!(debug_assertions) {
177 self.validate_lru();
178 }
179 }
180
181 pub fn is_empty(&self) -> bool {
182 self.head == u8::MAX
183 }
184
185 fn validate_lru(&self) {
187 trace!(
188 "{:?} LRU. head: {:?}, Actual data: {:?}",
189 self.regclass,
190 self.head,
191 self.data
192 );
193 if self.head != u8::MAX {
194 let mut node = self.data[self.head as usize].next;
195 let mut seen = FxHashSet::default();
196 while node != self.head {
197 if seen.contains(&node) {
198 panic!(
199 "Cycle detected in {:?} LRU.\n
200 head: {:?}, actual data: {:?}",
201 self.regclass, self.head, self.data
202 );
203 }
204 seen.insert(node);
205 node = self.data[node as usize].next;
206 }
207 for i in 0..self.data.len() {
208 if self.data[i].prev == u8::MAX && self.data[i].next == u8::MAX {
209 continue;
211 }
212 if self.data[i].prev == u8::MAX || self.data[i].next == u8::MAX {
213 panic!(
214 "Invalid LRU. p{} next or previous is an invalid value, but not both",
215 i
216 );
217 }
218 if self.data[self.data[i].prev as usize].next != i as u8 {
219 panic!(
220 "Invalid LRU. p{i} prev is p{:?}, but p{:?} next is {:?}",
221 self.data[i].prev,
222 self.data[i].prev,
223 self.data[self.data[i].prev as usize].next
224 );
225 }
226 if self.data[self.data[i].next as usize].prev != i as u8 {
227 panic!(
228 "Invalid LRU. p{i} next is p{:?}, but p{:?} prev is p{:?}",
229 self.data[i].next,
230 self.data[i].next,
231 self.data[self.data[i].next as usize].prev
232 );
233 }
234 }
235 }
236 }
237}
238
239impl fmt::Debug for Lru {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 use alloc::format;
242 let data_str = if self.head == u8::MAX {
243 format!("<empty>")
244 } else {
245 let mut data_str = format!("p{}", self.head);
246 let mut node = self.data[self.head as usize].next;
247 let mut seen = FxHashSet::default();
248 while node != self.head {
249 if seen.contains(&node) {
250 panic!(
251 "The {:?} LRU is messed up:
252 head: {:?}, {:?} -> p{node}, actual data: {:?}",
253 self.regclass, self.head, data_str, self.data
254 );
255 }
256 seen.insert(node);
257 data_str += &format!(" -> p{}", node);
258 node = self.data[node as usize].next;
259 }
260 data_str
261 };
262 f.debug_struct("Lru")
263 .field("head", if self.is_empty() { &"none" } else { &self.head })
264 .field("class", &self.regclass)
265 .field("data", &data_str)
266 .finish()
267 }
268}
269
270#[derive(Clone)]
271pub struct PartedByRegClass<T> {
272 pub items: [T; 3],
273}
274
275impl<T: Copy> Copy for PartedByRegClass<T> {}
276
277impl<T> Index<RegClass> for PartedByRegClass<T> {
278 type Output = T;
279
280 fn index(&self, index: RegClass) -> &Self::Output {
281 &self.items[index as usize]
282 }
283}
284
285impl<T> IndexMut<RegClass> for PartedByRegClass<T> {
286 fn index_mut(&mut self, index: RegClass) -> &mut Self::Output {
287 &mut self.items[index as usize]
288 }
289}
290
291impl<T: PartialEq> PartialEq for PartedByRegClass<T> {
292 fn eq(&self, other: &Self) -> bool {
293 self.items.eq(&other.items)
294 }
295}
296
297pub type Lrus = PartedByRegClass<Lru>;
299
300impl Lrus {
301 pub fn new(int_regs: &[PReg], float_regs: &[PReg], vec_regs: &[PReg]) -> Self {
302 Self {
303 items: [
304 Lru::new(RegClass::Int, int_regs),
305 Lru::new(RegClass::Float, float_regs),
306 Lru::new(RegClass::Vector, vec_regs),
307 ],
308 }
309 }
310}
311
312use core::fmt::{Debug, Display};
313
314impl<T: Display> Display for PartedByRegClass<T> {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 write!(
317 f,
318 "{{ int: {}, float: {}, vector: {} }}",
319 self.items[0], self.items[1], self.items[2]
320 )
321 }
322}
323
324impl<T: Debug> Debug for PartedByRegClass<T> {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 write!(
327 f,
328 "{{ int: {:?}, float: {:?}, vector: {:?} }}",
329 self.items[0], self.items[1], self.items[2]
330 )
331 }
332}