use crate::HashMap;
use crate::native::mir::*;
pub(super) struct SpillSlotAllocator {
pub(super) slots: HashMap<VReg, i32>,
pub(super) next_offset: i32,
}
impl SpillSlotAllocator {
pub(super) fn new() -> Self {
Self {
slots: HashMap::default(),
next_offset: 0,
}
}
pub(super) fn slot_for(&mut self, vreg: VReg) -> i32 {
*self.slots.entry(vreg).or_insert_with(|| {
let off = self.next_offset;
self.next_offset += 8; off
})
}
pub(super) fn total_size(&self) -> i32 {
self.next_offset
}
}
pub(super) fn make_spill(
vreg: VReg,
func: &MFunction,
slots: &mut SpillSlotAllocator,
) -> Option<MInst> {
let desc = func.spill_desc(vreg);
match desc.map(|d| &d.kind) {
Some(SpillKind::Remat { .. }) => {
None
}
Some(SpillKind::SimState { .. } | SpillKind::SimStateAlias { .. })
if desc.unwrap().spill_cost == 0 =>
{
None
}
Some(SpillKind::SimState { .. } | SpillKind::SimStateAlias { .. }) => {
let offset = slots.slot_for(vreg);
Some(MInst::Store {
base: BaseReg::StackFrame,
offset,
src: vreg,
size: OpSize::S64,
})
}
Some(SpillKind::Stack) | None => {
let offset = slots.slot_for(vreg);
Some(MInst::Store {
base: BaseReg::StackFrame,
offset,
src: vreg,
size: OpSize::S64,
})
}
}
}
pub(super) fn make_reload(vreg: VReg, func: &MFunction, slots: &mut SpillSlotAllocator) -> MInst {
let desc = func.spill_desc(vreg);
match desc.map(|d| &d.kind) {
Some(SpillKind::Remat { value }) => {
MInst::LoadImm {
dst: vreg,
value: *value,
}
}
Some(
SpillKind::SimState {
bit_offset,
width_bits,
..
}
| SpillKind::SimStateAlias {
bit_offset,
width_bits,
..
},
) if desc.unwrap().spill_cost == 0 => {
let byte_offset = (bit_offset / 8) as i32;
let op_size = match *width_bits {
0..=8 => OpSize::S8,
9..=16 => OpSize::S16,
17..=32 => OpSize::S32,
_ => OpSize::S64,
};
MInst::Load {
dst: vreg,
base: BaseReg::SimState,
offset: byte_offset,
size: op_size,
}
}
_ => {
let offset = slots.slot_for(vreg);
MInst::Load {
dst: vreg,
base: BaseReg::StackFrame,
offset,
size: OpSize::S64,
}
}
}
}