use std::collections::{BTreeMap, BTreeSet};
use crate::decompiler::cfg::BlockId;
use super::super::variable::{PhiNode, SsaVariable};
use super::state::{fresh_var, phi_var, SlotState};
use super::SsaBuilder;
impl SsaBuilder<'_> {
pub(super) fn compute_join_entry(
&self,
bid: BlockId,
exit_stacks: &BTreeMap<BlockId, Vec<SsaVariable>>,
) -> (Vec<SsaVariable>, Vec<PhiNode>) {
let preds = self.cfg.predecessors(bid);
if preds.is_empty() {
return (Vec::new(), Vec::new());
}
let mut entry = Vec::new();
let mut phis = Vec::new();
let mut depth = 0usize;
loop {
let mut operands: Vec<(BlockId, SsaVariable)> = Vec::new();
for pred in preds {
if let Some(stack) = exit_stacks.get(pred) {
if let Some(var) = stack.get(depth) {
operands.push((*pred, var.clone()));
}
}
}
if operands.is_empty() {
break;
}
let first = operands[0].1.clone();
if operands.iter().all(|(_, v)| *v == first) {
entry.push(first);
} else {
let target = phi_var(bid, depth);
let mut phi = PhiNode::new(target.clone());
for (pred, var) in &operands {
phi.add_operand(*pred, var.clone());
}
entry.push(target);
phis.push(phi);
}
depth += 1;
}
(entry, phis)
}
pub(super) fn compute_join_slots(
&self,
bid: BlockId,
exit_slots: &BTreeMap<BlockId, SlotState>,
versions: &mut BTreeMap<String, usize>,
) -> (SlotState, Vec<PhiNode>) {
let preds = self.cfg.predecessors(bid);
if preds.is_empty() {
return (SlotState::new(), Vec::new());
}
let mut names: BTreeSet<String> = BTreeSet::new();
for pred in preds {
if let Some(state) = exit_slots.get(pred) {
names.extend(state.keys().cloned());
}
}
let mut entry = SlotState::new();
let mut phis = Vec::new();
for name in names {
let operands: Vec<(BlockId, SsaVariable)> = preds
.iter()
.filter_map(|pred| {
exit_slots
.get(pred)
.and_then(|slots| slots.get(&name))
.map(|var| (*pred, var.clone()))
})
.collect();
if operands.is_empty() {
continue;
}
let first = operands[0].1.clone();
if operands.iter().all(|(_, v)| *v == first) {
entry.insert(name, first);
} else {
let target = fresh_var(versions, &name);
let mut phi = PhiNode::new(target.clone());
for (pred, var) in &operands {
phi.add_operand(*pred, var.clone());
}
entry.insert(name, target);
phis.push(phi);
}
}
(entry, phis)
}
}