1*2da108dfSSaúl Cabrera use crate::{
2*2da108dfSSaúl Cabrera     isa::reg::{Reg, RegClass},
3*2da108dfSSaúl Cabrera     regset::RegSet,
4*2da108dfSSaúl Cabrera };
5835abbcdSSaúl Cabrera 
6835abbcdSSaúl Cabrera /// The register allocator.
7835abbcdSSaúl Cabrera ///
8835abbcdSSaúl Cabrera /// The register allocator uses a single-pass algorithm;
9835abbcdSSaúl Cabrera /// its implementation uses a bitset as a freelist
10835abbcdSSaúl Cabrera /// to track per-class register availability.
11835abbcdSSaúl Cabrera ///
12835abbcdSSaúl Cabrera /// If a particular register is not available upon request
13835abbcdSSaúl Cabrera /// the register allocation will perform a "spill", essentially
14835abbcdSSaúl Cabrera /// moving Local and Register values in the stack to memory.
15835abbcdSSaúl Cabrera /// This processs ensures that whenever a register is requested,
16835abbcdSSaúl Cabrera /// it is going to be available.
17835abbcdSSaúl Cabrera pub(crate) struct RegAlloc {
18835abbcdSSaúl Cabrera     pub scratch: Reg,
19835abbcdSSaúl Cabrera     regset: RegSet,
20835abbcdSSaúl Cabrera }
21835abbcdSSaúl Cabrera 
22835abbcdSSaúl Cabrera impl RegAlloc {
23835abbcdSSaúl Cabrera     /// Create a new register allocator
24835abbcdSSaúl Cabrera     /// from a register set.
25835abbcdSSaúl Cabrera     pub fn new(regset: RegSet, scratch: Reg) -> Self {
26835abbcdSSaúl Cabrera         Self { regset, scratch }
27835abbcdSSaúl Cabrera     }
28835abbcdSSaúl Cabrera 
2914b39bc2SSaúl Cabrera     /// Allocate the next available register for the given class,
3014b39bc2SSaúl Cabrera     /// spilling if not available.
3114b39bc2SSaúl Cabrera     pub fn reg_for_class<F>(&mut self, class: RegClass, spill: &mut F) -> Reg
327ec92512SSaúl Cabrera     where
337ec92512SSaúl Cabrera         F: FnMut(&mut RegAlloc),
347ec92512SSaúl Cabrera     {
3514b39bc2SSaúl Cabrera         self.regset.reg_for_class(class).unwrap_or_else(|| {
367ec92512SSaúl Cabrera             spill(self);
3714b39bc2SSaúl Cabrera             self.regset.reg_for_class(class).unwrap_or_else(|| {
3814b39bc2SSaúl Cabrera                 panic!("expected register for class {:?}, to be avilable", class)
3914b39bc2SSaúl Cabrera             })
40835abbcdSSaúl Cabrera         })
41835abbcdSSaúl Cabrera     }
42835abbcdSSaúl Cabrera 
4314b39bc2SSaúl Cabrera     /// Returns true if the specified register is allocatable.
4414b39bc2SSaúl Cabrera     pub fn reg_available(&self, reg: Reg) -> bool {
4514b39bc2SSaúl Cabrera         self.regset.named_reg_available(reg)
46af4d94c8SSaúl Cabrera     }
47af4d94c8SSaúl Cabrera 
4814b39bc2SSaúl Cabrera     /// Request a specific register, spilling if not available.
4914b39bc2SSaúl Cabrera     pub fn reg<F>(&mut self, named: Reg, mut spill: F) -> Reg
507ec92512SSaúl Cabrera     where
517ec92512SSaúl Cabrera         F: FnMut(&mut RegAlloc),
527ec92512SSaúl Cabrera     {
5320c58362SSaúl Cabrera         // If the scratch register is explicitly requested
5420c58362SSaúl Cabrera         // just return it, it's usage should never cause spills.
5520c58362SSaúl Cabrera         if named == self.scratch {
5620c58362SSaúl Cabrera             return named;
5720c58362SSaúl Cabrera         }
5820c58362SSaúl Cabrera 
5914b39bc2SSaúl Cabrera         self.regset.reg(named).unwrap_or_else(|| {
607ec92512SSaúl Cabrera             spill(self);
61835abbcdSSaúl Cabrera             self.regset
6214b39bc2SSaúl Cabrera                 .reg(named)
6314b39bc2SSaúl Cabrera                 .expect(&format!("register {:?} to be available", named))
64835abbcdSSaúl Cabrera         })
65835abbcdSSaúl Cabrera     }
66835abbcdSSaúl Cabrera 
6714b39bc2SSaúl Cabrera     /// Free the given register.
6814b39bc2SSaúl Cabrera     pub fn free(&mut self, reg: Reg) {
6920c58362SSaúl Cabrera         if reg != self.scratch {
7014b39bc2SSaúl Cabrera             self.regset.free(reg);
71835abbcdSSaúl Cabrera         }
72835abbcdSSaúl Cabrera     }
7320c58362SSaúl Cabrera }
74