1 use crate::{isa::reg::Reg, regset::RegSet};
2 
3 /// The register allocator.
4 ///
5 /// The register allocator uses a single-pass algorithm;
6 /// its implementation uses a bitset as a freelist
7 /// to track per-class register availability.
8 ///
9 /// If a particular register is not available upon request
10 /// the register allocation will perform a "spill", essentially
11 /// moving Local and Register values in the stack to memory.
12 /// This processs ensures that whenever a register is requested,
13 /// it is going to be available.
14 pub(crate) struct RegAlloc {
15     pub scratch: Reg,
16     regset: RegSet,
17 }
18 
19 impl RegAlloc {
20     /// Create a new register allocator
21     /// from a register set.
22     pub fn new(regset: RegSet, scratch: Reg) -> Self {
23         Self { regset, scratch }
24     }
25 
26     /// Allocate the next available general purpose register,
27     /// spilling if none available.
28     pub fn any_gpr<F>(&mut self, spill: &mut F) -> Reg
29     where
30         F: FnMut(&mut RegAlloc),
31     {
32         self.regset.any_gpr().unwrap_or_else(|| {
33             spill(self);
34             self.regset.any_gpr().expect("any gpr to be available")
35         })
36     }
37 
38     /// Checks if a general purpose register is avaiable.
39     pub fn gpr_available(&self, reg: Reg) -> bool {
40         self.regset.named_gpr_available(reg.hw_enc() as u32)
41     }
42 
43     /// Request a specific general purpose register,
44     /// spilling if not available.
45     pub fn gpr<F>(&mut self, named: Reg, spill: &mut F) -> Reg
46     where
47         F: FnMut(&mut RegAlloc),
48     {
49         // If the scratch register is explicitly requested
50         // just return it, it's usage should never cause spills.
51         if named == self.scratch {
52             return named;
53         }
54 
55         self.regset.gpr(named).unwrap_or_else(|| {
56             spill(self);
57             self.regset
58                 .gpr(named)
59                 .expect(&format!("gpr {:?} to be available", named))
60         })
61     }
62 
63     /// Mark a particular general purpose register as available.
64     pub fn free_gpr(&mut self, reg: Reg) {
65         // Never mark the designated scratch register as allocatable.
66         if reg != self.scratch {
67             self.regset.free_gpr(reg);
68         }
69     }
70 }
71