use super::{LiveResult, reachable_prefix, expr_has_effect, collect_expr_refs};
use crate::ir::Node;
use std::collections::HashSet;
#[inline]
pub(crate) fn eliminate_dead_lets(nodes: &[Node], live_after: HashSet<String>) -> LiveResult {
let reachable_prefix = reachable_prefix(nodes);
let mut live = live_after;
let mut kept = Vec::with_capacity(reachable_prefix.len());
for node in reachable_prefix.iter().rev() {
match node {
Node::Let { name, value } if !live.contains(name) && !expr_has_effect(value) => {}
Node::Let { name, value } => {
live.remove(name);
collect_expr_refs(value, &mut live);
kept.push(Node::let_bind(name, value.clone()));
}
Node::Assign { name, value } => {
live.insert(name.clone());
collect_expr_refs(value, &mut live);
kept.push(Node::assign(name, value.clone()));
}
Node::Store {
buffer,
index,
value,
} => {
collect_expr_refs(index, &mut live);
collect_expr_refs(value, &mut live);
kept.push(Node::store(buffer, index.clone(), value.clone()));
}
Node::If {
cond,
then,
otherwise,
} => {
let then_result = eliminate_dead_lets(then, live.clone());
let otherwise_result = eliminate_dead_lets(otherwise, live.clone());
let mut branch_live = then_result.live_in;
branch_live.extend(otherwise_result.live_in);
collect_expr_refs(cond, &mut branch_live);
live = branch_live;
kept.push(Node::if_then_else(
cond.clone(),
then_result.nodes,
otherwise_result.nodes,
));
}
Node::Loop {
var,
from,
to,
body,
} => {
let mut body_live_after = live.clone();
body_live_after.insert(var.clone());
let body_result = eliminate_dead_lets(body, body_live_after);
live.extend(body_result.live_in);
live.remove(var);
collect_expr_refs(from, &mut live);
collect_expr_refs(to, &mut live);
kept.push(Node::loop_for(
var,
from.clone(),
to.clone(),
body_result.nodes,
));
}
Node::Block(block_nodes) => {
let block_result = eliminate_dead_lets(block_nodes, live.clone());
live.extend(block_result.live_in);
kept.push(Node::block(block_result.nodes));
}
Node::Return => kept.push(Node::Return),
Node::Barrier => kept.push(Node::Barrier),
}
}
kept.reverse();
LiveResult {
nodes: kept,
live_in: live,
}
}