Path: blob/main/winch/codegen/src/regalloc.rs
1691 views
use crate::{1codegen::CodeGenError,2isa::reg::{Reg, RegClass},3regset::{RegBitSet, RegSet},4};56use anyhow::{Result, anyhow};78/// The register allocator.9///10/// The register allocator uses a single-pass algorithm;11/// its implementation uses a bitset as a freelist12/// to track per-class register availability.13///14/// If a particular register is not available upon request15/// the register allocation will perform a "spill", essentially16/// moving Local and Register values in the stack to memory.17/// This process ensures that whenever a register is requested,18/// it is going to be available.19pub(crate) struct RegAlloc {20/// The register set.21regset: RegSet,22}2324impl RegAlloc {25/// Create a register allocator from a bit set for each register class.26pub fn from(gpr: RegBitSet, fpr: RegBitSet) -> Self {27let rs = RegSet::new(gpr, fpr);28Self { regset: rs }29}3031/// Allocate the next available register for the given class,32/// spilling if not available.33pub fn reg_for_class<F>(&mut self, class: RegClass, spill: &mut F) -> Result<Reg>34where35F: FnMut(&mut RegAlloc) -> Result<()>,36{37match self.regset.reg_for_class(class) {38Some(reg) => Ok(reg),39None => {40spill(self)?;41self.regset42.reg_for_class(class)43.ok_or_else(|| anyhow!(CodeGenError::expected_register_to_be_available()))44}45}46}4748/// Returns true if the specified register is allocatable.49pub fn reg_available(&self, reg: Reg) -> bool {50self.regset.named_reg_available(reg)51}5253/// Request a specific register, spilling if not available.54pub fn reg<F>(&mut self, named: Reg, mut spill: F) -> Result<Reg>55where56F: FnMut(&mut RegAlloc) -> Result<()>,57{58match self.regset.reg(named) {59Some(reg) => Ok(reg),60None => {61spill(self)?;62self.regset63.reg(named)64.ok_or_else(|| anyhow!(CodeGenError::expected_register_to_be_available()))65}66}67}6869/// Free the given register.70pub fn free(&mut self, reg: Reg) {71self.regset.free(reg);72}73}747576