use std::collections::{HashMap, HashSet};
use rucc_ir::{Extra, Func, FuncId, Inst, Linkage, Module, Opcode, Value};
use crate::CallGraph;
pub fn closed(module: &Module, graph: &CallGraph) -> Vec<FuncId> {
let mut closed = Vec::new();
for node in graph.nodes() {
if graph.address_taken(node) {
continue;
}
let Some(id) = graph.trusted_body(node) else { continue };
let func = &module[id];
if func.linkage != Linkage::Internal || func.signature().variadic {
continue;
}
let Some(entry) = func.entry() else { continue };
if func[entry].params.len() != func.signature().params.len() {
continue;
}
closed.push(id);
}
closed.sort_unstable_by_key(|id| id.raw());
closed
}
pub fn order(graph: &CallGraph, closed: &[FuncId]) -> Vec<Vec<FuncId>> {
let inside: HashSet<FuncId> = closed.iter().copied().collect();
let mut order = Vec::new();
for part in graph.components().iter().rev() {
let part: Vec<FuncId> = part
.iter()
.filter_map(|&node| graph.trusted_body(node))
.filter(|id| inside.contains(id))
.collect();
if !part.is_empty() {
order.push(part);
}
}
order
}
pub fn sites(module: &Module, closed: &[FuncId]) -> HashMap<FuncId, Sites> {
let mut where_defined: HashMap<_, FuncId> = HashMap::new();
for &id in closed {
where_defined.insert(module[id].name, id);
}
let mut sites: HashMap<FuncId, Sites> = HashMap::new();
for id in module.funcs() {
let func = &module[id];
if func.is_declaration() {
continue;
}
for block in func.blocks() {
for inst in func.insts(block) {
if !matches!(func[inst].opcode, Opcode::Call | Opcode::TailCall) {
continue;
}
let Extra::Call(at) = func[inst].extra else { continue };
let Some(callee) = func[at].callee else { continue };
let Some(&target) = where_defined.get(&callee) else { continue };
let entry = sites.entry(target).or_default();
if module[target].signature().params.len() != func[func[inst].args].len() {
entry.ragged = true;
continue;
}
entry.calls.push((id, inst));
}
}
}
sites
}
#[derive(Debug, Default)]
pub struct Sites {
pub calls: Vec<(FuncId, Inst)>,
pub ragged: bool,
}
pub fn operands(func: &Func) -> HashSet<Value> {
let mut read = HashSet::new();
for block in func.blocks() {
for inst in func.insts(block) {
read.extend(func[func[inst].args].iter().copied());
for edge in func.successors(inst) {
read.extend(func[edge.args].iter().copied());
}
}
}
read
}