use crate::regalloc::RegisterAllocator as MirRegisterAllocator;
use lamina_mir::register::{Register, RegisterClass, VirtualReg};
use lamina_platform::TargetOperatingSystem;
pub struct RiscVRegAlloc {
#[allow(dead_code)]
target_os: TargetOperatingSystem,
available_gprs: Vec<&'static str>,
allocated_gprs: std::collections::HashMap<&'static str, VirtualReg>,
stack_slots: std::collections::HashMap<VirtualReg, i32>,
next_stack_slot: i32,
}
impl Default for RiscVRegAlloc {
fn default() -> Self {
Self::new(TargetOperatingSystem::Linux)
}
}
impl RiscVRegAlloc {
const AVAILABLE_REGISTERS: &'static [&'static str] = &[
"x5", "x6", "x7", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", ];
pub fn new(target_os: TargetOperatingSystem) -> Self {
Self {
target_os,
available_gprs: Self::AVAILABLE_REGISTERS.to_vec(),
allocated_gprs: std::collections::HashMap::new(),
stack_slots: std::collections::HashMap::new(),
next_stack_slot: -8,
}
}
pub fn set_conservative_mode(&mut self) {
self.available_gprs = vec![
"x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", ];
}
pub fn get_stack_slot(&self, vreg: &VirtualReg) -> Option<i32> {
self.stack_slots.get(vreg).copied()
}
}
impl MirRegisterAllocator for RiscVRegAlloc {
type PhysReg = &'static str;
fn alloc_scratch(&mut self) -> Option<Self::PhysReg> {
for ® in &self.available_gprs {
if !self.allocated_gprs.contains_key(reg) {
return Some(reg);
}
}
self.available_gprs.first().copied()
}
fn free_scratch(&mut self, phys: Self::PhysReg) {
self.allocated_gprs.remove(phys);
}
fn get_mapping(&self, vreg: &VirtualReg) -> Option<Self::PhysReg> {
for (reg, allocated_vreg) in &self.allocated_gprs {
if allocated_vreg == vreg {
return Some(*reg);
}
}
None
}
fn ensure_mapping(&mut self, vreg: VirtualReg) -> Option<Self::PhysReg> {
if vreg.class != RegisterClass::Gpr {
return None;
}
if let Some(phys) = self.get_mapping(&vreg) {
return Some(phys);
}
if let Some(phys) = self.alloc_scratch() {
self.allocated_gprs.insert(phys, vreg);
return Some(phys);
}
let stack_slot = self.next_stack_slot;
self.stack_slots.insert(vreg, stack_slot);
self.next_stack_slot -= 8;
None }
fn mapped_for_register(&self, reg: &Register) -> Option<Self::PhysReg> {
match reg {
Register::Virtual(v) => self.get_mapping(v),
Register::Physical(p) => Some(p.name),
}
}
fn occupy(&mut self, _phys: Self::PhysReg) {}
fn release(&mut self, phys: Self::PhysReg) {
self.allocated_gprs.remove(phys);
}
fn is_occupied(&self, phys: Self::PhysReg) -> bool {
self.allocated_gprs.contains_key(phys)
}
}