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