use std::collections::BTreeMap;
use super::*;
impl StructuredBodyLowerer<'_, '_> {
pub(in crate::hir::analyze::structure) fn block_entry_expr_overrides(
&self,
block: BlockRef,
) -> Option<&BTreeMap<TempId, HirExpr>> {
self.overrides.block_entry_temp_exprs(block)
}
pub(in crate::hir::analyze::structure) fn block_redefines_reg(
&self,
block: BlockRef,
reg: Reg,
) -> bool {
let range = self.lowering.cfg.blocks[block.index()].instrs;
(range.start.index()..range.end()).any(|instr_index| {
let effect = &self.lowering.dataflow.instr_effects[instr_index];
effect.fixed_must_defs.contains(®) || effect.fixed_may_defs.contains(®)
})
}
pub(in crate::hir::analyze::structure) fn install_entry_override(
&mut self,
block: BlockRef,
reg: Reg,
expr: HirExpr,
) {
if self
.overrides
.carried_entry_expr(block, reg)
.is_some_and(|existing| *existing == expr)
{
return;
}
let source_temp = self.block_entry_source_temp(block, reg);
let carries_through_block = !self.block_redefines_reg(block, reg);
self.overrides.insert_entry_expr(
block,
reg,
expr.clone(),
source_temp,
carries_through_block,
);
if carries_through_block {
for edge_ref in &self.lowering.cfg.succs[block.index()] {
let successor = self.lowering.cfg.edges[edge_ref.index()].to;
if !self.lowering.cfg.reachable_blocks.contains(&successor) {
continue;
}
if self
.lowering
.dataflow
.phi_candidate_for_reg(successor, reg)
.is_none()
{
self.install_entry_override(successor, reg, expr.clone());
}
}
}
}
pub(in crate::hir::analyze::structure) fn replace_phi_with_entry_expr(
&mut self,
block: BlockRef,
phi_id: PhiId,
reg: Reg,
expr: HirExpr,
) {
self.overrides.suppress_phi(phi_id);
self.install_entry_override(block, reg, expr);
}
pub(in crate::hir::analyze::structure) fn replace_phi_with_entry_expr_if_local_use(
&mut self,
block: BlockRef,
phi_id: PhiId,
reg: Reg,
expr: HirExpr,
) {
if self.lowering.dataflow.phi_used_only_in_block(phi_id, block) {
self.replace_phi_with_entry_expr(block, phi_id, reg, expr);
} else {
self.overrides.insert_phi_expr(block, phi_id, expr);
}
}
pub(in crate::hir::analyze::structure) fn replace_phi_with_target_expr(
&mut self,
block: BlockRef,
phi_id: PhiId,
target: &HirLValue,
expr: HirExpr,
) {
let phi_temp = self.lowering.bindings.phi_temps[phi_id.index()];
if lvalue_as_expr(target) == Some(HirExpr::TempRef(phi_temp)) {
self.overrides.suppress_phi(phi_id);
} else {
self.overrides.insert_phi_expr(block, phi_id, expr);
}
}
fn block_entry_source_temp(&self, block: BlockRef, reg: Reg) -> Option<TempId> {
let range = self.lowering.cfg.blocks[block.index()].instrs;
if range.is_empty() {
return None;
}
let values = self
.lowering
.dataflow
.reaching_values_at(range.start)
.get(reg)?;
if values.len() != 1 {
return None;
}
Some(
match values
.iter()
.next()
.expect("len checked above, exactly one reaching value exists")
{
crate::structure::SsaValue::Def(def) => {
self.lowering.bindings.fixed_temps[def.index()]
}
crate::structure::SsaValue::Phi(phi) => {
self.lowering.bindings.phi_temps[phi.index()]
}
},
)
}
}