use crate::compiler::{RegOp, RegisterAllocator, SsaTape};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Clone, Default, Serialize, Deserialize)]
pub struct RegTape {
tape: Vec<RegOp>,
pub(super) slot_count: u32,
}
impl RegTape {
pub fn new<const N: usize>(ssa: &SsaTape) -> Self {
let mut alloc = RegisterAllocator::<N>::new(ssa.len());
for &op in ssa.iter() {
alloc.op(op)
}
alloc.finalize()
}
pub fn repack(&mut self) {
let map = self.repack_map();
for op in &mut self.tape {
op.visit_regs_mut(|reg| *reg = map[reg]);
}
}
pub fn repack_map(&self) -> HashMap<u8, u8> {
let mut reg_counts: HashMap<u8, usize> = HashMap::new();
for op in &self.tape {
op.visit_regs(|reg| *reg_counts.entry(reg).or_default() += 1);
}
let mut sorted = reg_counts
.into_iter()
.map(|(reg, count)| (std::cmp::Reverse(count), reg))
.collect::<Vec<_>>();
sorted.sort_unstable();
sorted
.into_iter()
.enumerate()
.map(|(i, (_count, reg))| (reg, u8::try_from(i).unwrap()))
.collect()
}
pub(crate) fn empty() -> Self {
Self {
tape: vec![],
slot_count: 0,
}
}
pub fn reset(&mut self) {
self.tape.clear();
self.slot_count = 0;
}
#[inline]
pub fn slot_count(&self) -> usize {
self.slot_count as usize
}
#[inline]
pub fn len(&self) -> usize {
self.tape.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.tape.is_empty()
}
#[inline]
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &RegOp> {
self.into_iter()
}
#[inline]
pub(crate) fn push(&mut self, op: RegOp) {
self.tape.push(op)
}
}
impl<'a> IntoIterator for &'a RegTape {
type Item = &'a RegOp;
type IntoIter = std::slice::Iter<'a, RegOp>;
fn into_iter(self) -> Self::IntoIter {
self.tape.iter()
}
}