use log::trace;
use std::collections::HashSet;
use std::hash::Hash;
use super::errors::SSAResult;
pub trait SSAConfig: Sized {
type Version;
type Variable: PartialEq + Eq + Hash + Clone;
type Environment: SSAEnvironment;
type Statement: SSAStatement<Self>;
type BasicBlock: SSABasicBlock<Self> + DirectedGraphNode;
}
pub trait SSAEnvironment {
fn add_variable_scope(&mut self);
fn remove_variable_scope(&mut self);
}
pub trait SSABasicBlock<Cfg: SSAConfig>: DirectedGraphNode {
fn prepend_statement(&mut self, stmt: Cfg::Statement);
fn statements<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Cfg::Statement> + 'a>;
fn statements_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = &'a mut Cfg::Statement> + 'a>;
fn variables_written(&self) -> HashSet<Cfg::Variable> {
self.statements().fold(HashSet::new(), |mut vars, stmt| {
vars.extend(stmt.variables_written());
vars
})
}
fn has_phi_statement(&self, var: &Cfg::Variable) -> bool {
self.statements().any(|stmt| stmt.is_phi_statement_for(var))
}
fn insert_phi_statement(&mut self, var: &Cfg::Variable, env: &Cfg::Environment) {
self.prepend_statement(SSAStatement::new_phi_statement(var, env));
}
fn update_phi_statements(&mut self, env: &Cfg::Environment) {
trace!("updating phi expression arguments in block {}", self.index());
for stmt in self.statements_mut() {
if stmt.is_phi_statement() {
stmt.ensure_phi_argument(env);
} else {
break;
}
}
}
fn insert_ssa_variables(&mut self, env: &mut Cfg::Environment) -> SSAResult<()> {
trace!("inserting SSA variables in block {}", self.index());
for stmt in self.statements_mut() {
stmt.insert_ssa_variables(env)?;
}
Ok(())
}
}
pub trait SSAStatement<Cfg: SSAConfig>: Clone {
fn variables_written(&self) -> HashSet<Cfg::Variable>;
fn new_phi_statement(name: &Cfg::Variable, env: &Cfg::Environment) -> Self;
fn is_phi_statement(&self) -> bool;
fn is_phi_statement_for(&self, var: &Cfg::Variable) -> bool;
fn ensure_phi_argument(&mut self, env: &Cfg::Environment);
fn insert_ssa_variables(&mut self, env: &mut Cfg::Environment) -> SSAResult<()>;
}
pub type Index = usize;
pub type IndexSet = HashSet<Index>;
pub trait DirectedGraphNode {
fn index(&self) -> Index;
fn predecessors(&self) -> &IndexSet;
fn successors(&self) -> &IndexSet;
}