use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use super::{SsaBlock, UseSite};
use crate::decompiler::cfg::ssa::dominance::DominanceInfo;
use crate::decompiler::cfg::ssa::variable::SsaVariable;
use crate::decompiler::cfg::{BlockId, Cfg};
#[derive(Debug, Clone)]
pub struct SsaForm {
pub cfg: Cfg,
pub dominance: DominanceInfo,
pub blocks: BTreeMap<BlockId, SsaBlock>,
pub definitions: BTreeMap<SsaVariable, BlockId>,
pub uses: BTreeMap<SsaVariable, BTreeSet<UseSite>>,
}
impl SsaForm {
#[must_use]
pub fn new(cfg: Cfg, dominance: DominanceInfo) -> Self {
Self {
cfg,
dominance,
blocks: BTreeMap::new(),
definitions: BTreeMap::new(),
uses: BTreeMap::new(),
}
}
pub fn add_block(&mut self, id: BlockId, block: SsaBlock) {
self.blocks.insert(id, block);
}
#[must_use]
pub fn block(&self, id: BlockId) -> Option<&SsaBlock> {
self.blocks.get(&id)
}
pub fn blocks_iter(&self) -> impl Iterator<Item = (&BlockId, &SsaBlock)> {
self.blocks.iter()
}
#[must_use]
pub fn block_count(&self) -> usize {
self.blocks.len()
}
pub fn add_definition(&mut self, var: SsaVariable, block: BlockId) {
self.definitions.insert(var, block);
}
pub fn add_use(&mut self, var: SsaVariable, site: UseSite) {
self.uses.entry(var).or_default().insert(site);
}
#[must_use]
pub fn uses_of(&self, var: &SsaVariable) -> Option<&BTreeSet<UseSite>> {
self.uses.get(var)
}
#[must_use]
pub fn render(&self) -> String {
let mut output = String::new();
use std::fmt::Write;
writeln!(output, "// SSA Form - {} blocks", self.block_count()).unwrap();
writeln!(output).unwrap();
for (block_id, block) in self.blocks_iter() {
writeln!(output, "block {:?}:", block_id).unwrap();
write!(output, "{}", block).unwrap();
}
output
}
#[must_use]
pub fn stats(&self) -> SsaStats {
let total_phi_nodes: usize = self.blocks.values().map(SsaBlock::phi_count).sum();
let total_statements: usize = self.blocks.values().map(SsaBlock::stmt_count).sum();
let total_variables = self.definitions.len();
SsaStats {
block_count: self.block_count(),
total_phi_nodes,
total_statements,
total_variables,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SsaStats {
pub block_count: usize,
pub total_phi_nodes: usize,
pub total_statements: usize,
pub total_variables: usize,
}
impl fmt::Display for SsaStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"SSA Stats: {} blocks, {} φ nodes, {} statements, {} variables",
self.block_count, self.total_phi_nodes, self.total_statements, self.total_variables
)
}
}