use crate::mir::{Register, VirtualReg};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PhysRegHandle {
Named(&'static str),
}
impl PhysRegHandle {
pub fn as_named(self) -> Option<&'static str> {
match self {
PhysRegHandle::Named(name) => Some(name),
}
}
}
pub trait PhysRegConvertible: Copy + Eq {
fn into_handle(self) -> PhysRegHandle;
fn from_handle(handle: PhysRegHandle) -> Option<Self>
where
Self: Sized;
}
impl PhysRegConvertible for &'static str {
fn into_handle(self) -> PhysRegHandle {
PhysRegHandle::Named(self)
}
fn from_handle(handle: PhysRegHandle) -> Option<Self> {
match handle {
PhysRegHandle::Named(name) => Some(name),
}
}
}
pub trait RegisterAllocator {
type PhysReg: PhysRegConvertible;
fn alloc_scratch(&mut self) -> Option<Self::PhysReg>;
fn free_scratch(&mut self, phys: Self::PhysReg);
fn get_mapping(&self, vreg: &VirtualReg) -> Option<Self::PhysReg>;
fn ensure_mapping(&mut self, vreg: VirtualReg) -> Option<Self::PhysReg>;
fn mapped_for_register(&self, reg: &Register) -> Option<Self::PhysReg>;
fn occupy(&mut self, phys: Self::PhysReg);
fn release(&mut self, phys: Self::PhysReg);
fn is_occupied(&self, phys: Self::PhysReg) -> bool;
}
pub trait RegisterAllocatorDyn {
fn alloc_scratch_dyn(&mut self) -> Option<PhysRegHandle>;
fn free_scratch_dyn(&mut self, phys: PhysRegHandle);
fn get_mapping_dyn(&self, vreg: &VirtualReg) -> Option<PhysRegHandle>;
fn ensure_mapping_dyn(&mut self, vreg: VirtualReg) -> Option<PhysRegHandle>;
fn mapped_for_register_dyn(&self, reg: &Register) -> Option<PhysRegHandle>;
fn occupy_dyn(&mut self, phys: PhysRegHandle);
fn release_dyn(&mut self, phys: PhysRegHandle);
fn is_occupied_dyn(&self, phys: PhysRegHandle) -> bool;
}
impl<T> RegisterAllocatorDyn for T
where
T: RegisterAllocator,
{
fn alloc_scratch_dyn(&mut self) -> Option<PhysRegHandle> {
self.alloc_scratch().map(|reg| reg.into_handle())
}
fn free_scratch_dyn(&mut self, phys: PhysRegHandle) {
if let Some(reg) = <T::PhysReg as PhysRegConvertible>::from_handle(phys) {
self.free_scratch(reg);
} else {
debug_assert!(false, "failed to decode physical register handle");
}
}
fn get_mapping_dyn(&self, vreg: &VirtualReg) -> Option<PhysRegHandle> {
self.get_mapping(vreg).map(|reg| reg.into_handle())
}
fn ensure_mapping_dyn(&mut self, vreg: VirtualReg) -> Option<PhysRegHandle> {
self.ensure_mapping(vreg).map(|reg| reg.into_handle())
}
fn mapped_for_register_dyn(&self, reg: &Register) -> Option<PhysRegHandle> {
self.mapped_for_register(reg).map(|r| r.into_handle())
}
fn occupy_dyn(&mut self, phys: PhysRegHandle) {
if let Some(reg) = <T::PhysReg as PhysRegConvertible>::from_handle(phys) {
self.occupy(reg);
} else {
debug_assert!(false, "failed to decode physical register handle");
}
}
fn release_dyn(&mut self, phys: PhysRegHandle) {
if let Some(reg) = <T::PhysReg as PhysRegConvertible>::from_handle(phys) {
self.release(reg);
} else {
debug_assert!(false, "failed to decode physical register handle");
}
}
fn is_occupied_dyn(&self, phys: PhysRegHandle) -> bool {
if let Some(reg) = <T::PhysReg as PhysRegConvertible>::from_handle(phys) {
self.is_occupied(reg)
} else {
debug_assert!(false, "failed to decode physical register handle");
false
}
}
}