202 lines
6.9 KiB
Rust
202 lines
6.9 KiB
Rust
use std::{cell::RefCell, collections::BTreeMap, fmt::Display, rc::{Rc, Weak}};
|
|
|
|
use crate::ir::types::Variable;
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Register {
|
|
name: &'static str,
|
|
}
|
|
impl Display for Register {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.name)
|
|
}
|
|
}
|
|
macro_rules! register_declare {
|
|
($($reg:ident => $name:expr),*) => {
|
|
$(
|
|
pub const $reg: Register = Register { name: $name };
|
|
)*
|
|
};
|
|
}
|
|
register_declare! {
|
|
REG_R0 => "r0",
|
|
REG_R1 => "r1",
|
|
REG_R2 => "r2",
|
|
REG_R3 => "r3",
|
|
REG_R4 => "r4",
|
|
REG_R5 => "r5",
|
|
REG_R6 => "r6",
|
|
REG_R7 => "r7",
|
|
REG_R8 => "r8",
|
|
REG_R9 => "r9",
|
|
REG_R10 => "r10",
|
|
REG_R11 => "r11",
|
|
REG_R12 => "r12",
|
|
REG_SP => "sp",
|
|
REG_LR => "lr",
|
|
REG_PC => "pc",
|
|
REG_FP => "fp"
|
|
}
|
|
|
|
pub const REGISTERS: &[Register] = &[
|
|
REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7, REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_SP, REG_LR, REG_PC, REG_FP
|
|
];
|
|
|
|
pub const REGISTERS_CAN_ALLOC: &[Register] = &[
|
|
REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7, REG_R8, REG_R9, REG_R10, REG_R12
|
|
];
|
|
pub struct RegisterAlloc {
|
|
allocator: Weak<RefCell<RegisterAllocatorInner>>,
|
|
pub reg: Register,
|
|
pub is_reused: bool,
|
|
}
|
|
impl Drop for RegisterAlloc {
|
|
fn drop(&mut self) {
|
|
if let Some(allocator) = self.allocator.upgrade() {
|
|
let mut allocator = allocator.borrow_mut();
|
|
allocator.mark_unused(self.reg);
|
|
}
|
|
}
|
|
}
|
|
pub enum RegisterUseKind {
|
|
Designated,
|
|
UsedByVariable(Variable),
|
|
AllocatedToVariable(Variable),
|
|
Free,
|
|
}
|
|
struct RegisterAllocatorInner {
|
|
register_map: BTreeMap<Register, RegisterUseKind>,
|
|
variable_to_register: BTreeMap<Variable, Register>,
|
|
}
|
|
pub struct RegisterAllocator {
|
|
// register_map: BTreeMap<Register, RegisterUseKind>,
|
|
// variable_to_register: BTreeMap<Variable, Register>,
|
|
inner: Rc<RefCell<RegisterAllocatorInner>>,
|
|
}
|
|
impl RegisterAllocatorInner {
|
|
fn mark_unused(&mut self, reg: Register) {
|
|
if let Some(use_kind) = self.register_map.get_mut(®) {
|
|
match use_kind {
|
|
RegisterUseKind::Designated => {
|
|
*use_kind = RegisterUseKind::Free;
|
|
},
|
|
RegisterUseKind::UsedByVariable(var) => {
|
|
*use_kind = RegisterUseKind::AllocatedToVariable(*var);
|
|
},
|
|
_ => panic!("Trying to mark a register as unused that is not in use"),
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
impl RegisterAllocator {
|
|
pub fn new() -> Self {
|
|
let mut register_map = BTreeMap::new();
|
|
for ® in REGISTERS_CAN_ALLOC {
|
|
register_map.insert(reg, RegisterUseKind::Free);
|
|
}
|
|
Self {
|
|
inner: Rc::new(RefCell::new(RegisterAllocatorInner {
|
|
register_map,
|
|
variable_to_register: BTreeMap::new(),
|
|
})),
|
|
}
|
|
}
|
|
|
|
pub fn alloc(&mut self, var: Variable) -> Option<RegisterAlloc> {
|
|
let mut inner = self.inner.borrow_mut();
|
|
if let Some(®) = inner.variable_to_register.get(&var) {
|
|
// Variable already has a register allocated
|
|
let use_kind = inner.register_map.get_mut(®).expect("Inconsistent state: variable has a register but it's not in the register map");
|
|
assert!(matches!(use_kind, RegisterUseKind::UsedByVariable(v) | RegisterUseKind::AllocatedToVariable(v) if *v == var));
|
|
*use_kind = RegisterUseKind::UsedByVariable(var);
|
|
return Some(RegisterAlloc {
|
|
allocator: Rc::downgrade(&self.inner),
|
|
reg,
|
|
is_reused: true,
|
|
});
|
|
}
|
|
// Find a free register
|
|
for (®, use_kind) in inner.register_map.iter_mut() {
|
|
// Find free register first
|
|
if let RegisterUseKind::Free = use_kind {
|
|
*use_kind = RegisterUseKind::UsedByVariable(var);
|
|
inner.variable_to_register.insert(var, reg);
|
|
return Some(RegisterAlloc {
|
|
allocator: Rc::downgrade(&self.inner),
|
|
reg,
|
|
is_reused: false,
|
|
});
|
|
}
|
|
}
|
|
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
|
for (®, use_kind) in register_map.iter_mut() {
|
|
// Find allocated register then
|
|
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
|
|
assert!(variable_to_register.remove(&ori_var).is_some());
|
|
*use_kind = RegisterUseKind::UsedByVariable(var);
|
|
variable_to_register.insert(var, reg);
|
|
return Some(RegisterAlloc {
|
|
allocator: Rc::downgrade(&self.inner),
|
|
reg,
|
|
is_reused: false,
|
|
});
|
|
}
|
|
}
|
|
// No free register available
|
|
None
|
|
}
|
|
|
|
pub fn alloc_reg(&mut self, reg: Register) -> Option<RegisterAlloc> {
|
|
let mut inner = self.inner.borrow_mut();
|
|
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
|
let use_kind = register_map.get_mut(®).expect("Trying to allocate a register that is not in the register map");
|
|
match use_kind {
|
|
RegisterUseKind::Free => {
|
|
*use_kind = RegisterUseKind::Designated;
|
|
return Some(RegisterAlloc {
|
|
allocator: Rc::downgrade(&self.inner),
|
|
reg,
|
|
is_reused: false,
|
|
});
|
|
},
|
|
RegisterUseKind::UsedByVariable(_var) => {
|
|
return None;
|
|
},
|
|
RegisterUseKind::AllocatedToVariable(var) => {
|
|
variable_to_register.remove(var);
|
|
*use_kind = RegisterUseKind::Designated;
|
|
return Some(RegisterAlloc {
|
|
allocator: Rc::downgrade(&self.inner),
|
|
reg,
|
|
is_reused: false,
|
|
});
|
|
},
|
|
RegisterUseKind::Designated => {
|
|
return None;
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
pub fn alloc_any(&mut self) -> Option<Register> {
|
|
let mut inner = self.inner.borrow_mut();
|
|
|
|
for (®, use_kind) in inner.register_map.iter_mut() {
|
|
if let RegisterUseKind::Free = use_kind {
|
|
*use_kind = RegisterUseKind::Designated;
|
|
return Some(reg);
|
|
}
|
|
}
|
|
let RegisterAllocatorInner{register_map, variable_to_register} = &mut *inner;
|
|
for (®, use_kind) in register_map.iter_mut() {
|
|
if let RegisterUseKind::AllocatedToVariable(ori_var) = use_kind {
|
|
variable_to_register.remove(&ori_var);
|
|
*use_kind = RegisterUseKind::Designated;
|
|
return Some(reg);
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
} |