use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
use crate::analysis::UseLocation;
use crate::{BlockEnd, Lowered, VariableId};
pub struct UseSites {
sites: Vec<OrderedHashMap<UseLocation, usize>>,
}
impl UseSites {
pub fn analyze(lowered: &Lowered<'_>) -> Self {
let mut sites: Vec<OrderedHashMap<UseLocation, usize>> =
(0..lowered.variables.len()).map(|_| OrderedHashMap::default()).collect();
for (block_id, block) in lowered.blocks.iter() {
for (stmt_idx, stmt) in block.statements.iter().enumerate() {
let loc = UseLocation::Statement((block_id, stmt_idx));
for input in stmt.inputs() {
*sites[input.var_id.index()].entry(loc).or_default() += 1;
}
}
let end_loc = UseLocation::BlockEnd(block_id);
match &block.end {
BlockEnd::Return(returns, _) => {
for ret in returns {
*sites[ret.var_id.index()].entry(end_loc).or_default() += 1;
}
}
BlockEnd::Panic(var) => {
*sites[var.var_id.index()].entry(end_loc).or_default() += 1;
}
BlockEnd::Goto(_, remapping) => {
for (_, src) in remapping.iter() {
*sites[src.var_id.index()].entry(end_loc).or_default() += 1;
}
}
BlockEnd::Match { info } => {
for input in info.inputs() {
*sites[input.var_id.index()].entry(end_loc).or_default() += 1;
}
}
BlockEnd::NotSet => {}
}
}
Self { sites }
}
pub fn use_count(&self, var: VariableId) -> usize {
self.sites[var.index()].iter().map(|(_, count)| *count).sum()
}
pub fn move_uses(&mut self, from: VariableId, to: VariableId, loc: UseLocation) {
let Entry::Occupied(entry) = self.sites[from.index()].entry(loc) else {
return;
};
let count = entry.swap_remove();
*self.sites[to.index()].entry(loc).or_default() += count;
}
pub fn use_locs(
&self,
var: VariableId,
) -> impl ExactSizeIterator<Item = (UseLocation, usize)> + '_ {
self.sites[var.index()].iter().map(|(loc, count)| (*loc, *count))
}
}
impl std::fmt::Debug for UseSites {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut list = f.debug_list();
for (idx, sites) in self.sites.iter().enumerate() {
let locs: Vec<_> = sites.iter().collect();
list.entry(&format_args!("v{idx}: {locs:?}"));
}
list.finish()
}
}