use std::collections::HashMap;
use rucc_ir::{Block, Func, Inst, Value};
#[must_use]
pub fn count(func: &Func) -> Vec<u32> {
let mut uses = vec![0u32; func.counts().values];
for block in func.blocks().collect::<Vec<Block>>() {
for inst in func.insts(block).collect::<Vec<Inst>>() {
operands(func, inst, |value| uses[value.index()] += 1);
}
}
uses
}
pub fn operands(func: &Func, inst: Inst, mut each: impl FnMut(Value)) {
for &value in &func[func[inst].args] {
each(value);
}
for call in func.successors(inst) {
for &value in &func[call.args] {
each(value);
}
}
}
pub fn substitute(func: &mut Func, forward: &HashMap<Value, Value>) {
let with = |value: Value| chase(forward, value);
for block in func.blocks().collect::<Vec<Block>>() {
for inst in func.insts(block).collect::<Vec<Inst>>() {
let args = func[inst].args;
func.rewrite(args, with);
for call in func.successors(inst).collect::<Vec<_>>() {
func.rewrite(call.args, with);
}
}
}
let mut moving: Vec<Value> = forward.keys().copied().collect();
moving.sort_unstable();
for from in moving {
func.rename_value(from, chase(forward, from));
}
}
#[must_use]
pub fn chase(forward: &HashMap<Value, Value>, value: Value) -> Value {
let mut value = value;
while let Some(&next) = forward.get(&value) {
value = next;
}
value
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use rucc_base::Interner;
use rucc_ir::{Builder, Func, Signature, Type, Value};
use super::substitute;
fn three(names: &mut Interner) -> (Func, Vec<Value>) {
let i32_ = Type::int(32);
let sig = Signature::new().with_returns(&[i32_]);
let mut func = Func::new(names.intern("three"), sig);
let entry = func.create_block();
let mut build = Builder::new(&mut func, entry);
let held: Vec<Value> = (1i128..=3).map(|value| build.iconst(i32_, value)).collect();
build.ret(&[held[0]]);
(func, held)
}
#[test]
fn a_substitution_moves_a_name_to_the_value_the_readers_were_pointed_at() {
let mut names = Interner::new();
let (mut func, held) = three(&mut names);
func.declare_value(held[0], 7);
func.declare_value(held[1], 8);
let forward = HashMap::from([(held[0], held[1]), (held[1], held[2])]);
substitute(&mut func, &forward);
let entry = func.blocks().next().expect("a block");
let ret = func.insts(entry).last().expect("the return");
assert_eq!(func[func[ret].args], [held[2]], "the readers went to the end of the chain");
assert_eq!(func.value_decls(held[2]).collect::<Vec<u32>>(), vec![7, 8]);
assert_eq!(func.value_decls(held[0]).count(), 0, "nothing is left on what is read no more");
assert_eq!(func.value_decls(held[1]).count(), 0);
}
}