1 use crate::{ 2 isa::reg::{Reg, RegClass}, 3 regset::{RegBitSet, RegSet}, 4 }; 5 6 /// The register allocator. 7 /// 8 /// The register allocator uses a single-pass algorithm; 9 /// its implementation uses a bitset as a freelist 10 /// to track per-class register availability. 11 /// 12 /// If a particular register is not available upon request 13 /// the register allocation will perform a "spill", essentially 14 /// moving Local and Register values in the stack to memory. 15 /// This processs ensures that whenever a register is requested, 16 /// it is going to be available. 17 pub(crate) struct RegAlloc { 18 /// The register set. 19 regset: RegSet, 20 } 21 22 impl RegAlloc { 23 /// Create a register allocator from a bit set for each register class. 24 pub fn from(gpr: RegBitSet, fpr: RegBitSet) -> Self { 25 let rs = RegSet::new(gpr, fpr); 26 Self { regset: rs } 27 } 28 29 /// Allocate the next available register for the given class, 30 /// spilling if not available. 31 pub fn reg_for_class<F>(&mut self, class: RegClass, spill: &mut F) -> Reg 32 where 33 F: FnMut(&mut RegAlloc), 34 { 35 self.regset.reg_for_class(class).unwrap_or_else(|| { 36 spill(self); 37 self.regset.reg_for_class(class).unwrap_or_else(|| { 38 panic!("expected register for class {:?}, to be avilable", class) 39 }) 40 }) 41 } 42 43 /// Returns true if the specified register is allocatable. 44 pub fn reg_available(&self, reg: Reg) -> bool { 45 self.regset.named_reg_available(reg) 46 } 47 48 /// Request a specific register, spilling if not available. 49 pub fn reg<F>(&mut self, named: Reg, mut spill: F) -> Reg 50 where 51 F: FnMut(&mut RegAlloc), 52 { 53 self.regset.reg(named).unwrap_or_else(|| { 54 spill(self); 55 self.regset 56 .reg(named) 57 .expect(&format!("register {:?} to be available", named)) 58 }) 59 } 60 61 /// Free the given register. 62 pub fn free(&mut self, reg: Reg) { 63 self.regset.free(reg); 64 } 65 } 66