use {
crate::{
frontend::FreshVariable,
ir::{FreshRegister, Instruction},
reification::ReifiedRegister,
FreshAllocator,
},
std::{
collections::{HashSet, VecDeque},
fmt::Display,
},
};
struct Seen(HashSet<FreshRegister>);
impl Default for Seen {
fn default() -> Self {
Self::new()
}
}
impl Seen {
pub fn new() -> Self {
Self(HashSet::new())
}
fn mark_register(&mut self, fresh: &ReifiedRegister<FreshRegister>) -> bool {
self.0.insert(fresh.reg)
}
}
#[derive(Clone, Copy)]
pub struct Lifetime {
pub(crate) begin: usize,
pub(crate) end: usize,
}
pub struct Lifetimes(Vec<Lifetime>);
impl Lifetimes {
pub fn new(nr_fresh_registers: usize) -> Self {
Self(vec![
Lifetime {
begin: usize::MAX,
end: usize::MAX,
};
nr_fresh_registers
])
}
}
impl std::ops::Index<FreshRegister> for Lifetimes {
type Output = Lifetime;
fn index(&self, index: FreshRegister) -> &Self::Output {
&self.0[index.0 as usize]
}
}
impl std::ops::IndexMut<FreshRegister> for Lifetimes {
fn index_mut(&mut self, index: FreshRegister) -> &mut Self::Output {
&mut self.0[index.0 as usize]
}
}
pub fn liveness_analysis(
alloc: &FreshAllocator, output_variables: &[FreshVariable],
instructions: &[Instruction<FreshRegister>],
) -> (VecDeque<HashSet<FreshRegister>>, Lifetimes) {
let mut seen_registers = Seen::new();
output_variables.iter().for_each(|variable| {
variable.registers.iter().for_each(|register| {
seen_registers.mark_register(register);
});
});
let mut lifetimes = Lifetimes::new(alloc.allocated());
let mut commands = VecDeque::new();
for (line, instruction) in instructions.iter().enumerate().rev() {
let registers: HashSet<_> = instruction.extract_registers().map(|tr| tr.reg).collect();
let release: HashSet<_> = registers.difference(&seen_registers.0).copied().collect();
instruction.results.iter().for_each(|dest| {
let dest = dest.reg;
if release.contains(&dest) {
print_instructions(instructions);
panic!("{line}: {instruction:?} does not use the destination")
};
let lifetime = &mut lifetimes[dest];
lifetime.begin = line;
});
release.iter().for_each(|reg| {
let lifetime = &mut lifetimes[*reg];
lifetime.end = line;
seen_registers.0.insert(*reg);
});
commands.push_front(release);
}
(commands, lifetimes)
}
fn print_instructions<R: Display>(instructions: &[Instruction<R>]) {
instructions
.iter()
.enumerate()
.for_each(|(line, inst)| println!("{line}: {inst}"));
}