use std::collections::{BTreeSet, HashMap};
use either::Either;
use indexmap::IndexSet;
use sway_types::FxIndexSet;
use crate::asm_lang::{ControlFlowOp, Label, Op, VirtualRegister};
pub(crate) fn liveness_analysis(
ops: &[Op],
ignore_constant_regs: bool,
) -> Vec<BTreeSet<VirtualRegister>> {
let mut live_in: Vec<FxIndexSet<VirtualRegister>> = vec![IndexSet::default(); ops.len()];
let mut live_out: Vec<BTreeSet<VirtualRegister>> = vec![BTreeSet::default(); ops.len()];
let mut label_to_index: HashMap<Label, usize> = HashMap::new();
for (idx, op) in ops.iter().enumerate() {
if let Either::Right(ControlFlowOp::Label(op_label)) = op.opcode {
label_to_index.insert(op_label, idx);
}
}
let mut modified = true;
while modified {
modified = false;
for (ix, op) in ops.iter().rev().enumerate() {
let mut local_modified = false;
let rev_ix = ops.len() - ix - 1;
let mut op_use = op.use_registers();
let mut op_def = op.def_registers();
if ignore_constant_regs {
op_use.retain(|®| reg.is_virtual());
op_def.retain(|®| reg.is_virtual());
}
for s in &op.successors(rev_ix, ops, &label_to_index) {
for l in live_in[*s].iter() {
local_modified |= live_out[rev_ix].insert(l.clone());
}
}
for u in op_use {
local_modified |= live_in[rev_ix].insert(u.clone());
}
for l in live_out[rev_ix].iter() {
if !op_def.contains(&l) {
local_modified |= live_in[rev_ix].insert(l.clone());
}
}
modified |= local_modified;
}
}
live_out
}