use std::collections::BTreeSet;
use crate::hir::common::{HirBlock, HirExpr, HirLValue, HirProto, HirStmt, TempId};
use super::visit::{HirVisitor, visit_proto};
use super::walk::{HirRewritePass, rewrite_proto};
#[cfg(test)]
mod tests;
pub(super) fn remove_dead_temp_materializations_in_proto(proto: &mut HirProto) -> bool {
let live_reads = collect_live_temp_reads(proto);
let mut pass = DeadTempPass {
live_reads: &live_reads,
};
rewrite_proto(proto, &mut pass)
}
struct DeadTempPass<'a> {
live_reads: &'a BTreeSet<TempId>,
}
impl HirRewritePass for DeadTempPass<'_> {
fn rewrite_block(&mut self, block: &mut HirBlock) -> bool {
let original_len = block.stmts.len();
block
.stmts
.retain(|stmt| !is_dead_pure_temp_assignment(stmt, self.live_reads));
block.stmts.len() != original_len
}
}
fn collect_live_temp_reads(proto: &HirProto) -> BTreeSet<TempId> {
let mut collector = TempReadCollector::default();
visit_proto(proto, &mut collector);
collector.reads
}
#[derive(Default)]
struct TempReadCollector {
reads: BTreeSet<TempId>,
}
impl HirVisitor for TempReadCollector {
fn visit_expr(&mut self, expr: &HirExpr) {
if let HirExpr::TempRef(temp) = expr {
self.reads.insert(*temp);
}
}
}
fn is_dead_pure_temp_assignment(stmt: &HirStmt, live_reads: &BTreeSet<TempId>) -> bool {
let HirStmt::Assign(assign) = stmt else {
return false;
};
let ([HirLValue::Temp(temp)], [value]) = (assign.targets.as_slice(), assign.values.as_slice())
else {
return false;
};
!live_reads.contains(temp) && is_pure_value(value)
}
fn is_pure_value(expr: &HirExpr) -> bool {
matches!(
expr,
HirExpr::Nil
| HirExpr::Boolean(_)
| HirExpr::Integer(_)
| HirExpr::Number(_)
| HirExpr::String(_)
| HirExpr::Int64(_)
| HirExpr::UInt64(_)
| HirExpr::Complex { .. }
| HirExpr::ParamRef(_)
| HirExpr::LocalRef(_)
| HirExpr::UpvalueRef(_)
| HirExpr::TempRef(_)
| HirExpr::GlobalRef(_)
| HirExpr::VarArg
| HirExpr::Unresolved(_)
)
}