use open_hypergraphs::array::vec::VecKind;
use open_hypergraphs::{lax, strict};
use std::fmt::{self, Debug, Display};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SSA<O, A> {
pub op: A,
pub edge_id: lax::EdgeId,
pub sources: Vec<(lax::NodeId, O)>, pub targets: Vec<(lax::NodeId, O)>, }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SSAError {
Cycle,
}
pub fn parallel_ssa<O: Clone, A: Clone>(
f: strict::OpenHypergraph<VecKind, O, A>,
) -> Result<Vec<Vec<SSA<O, A>>>, SSAError> {
let (result, unvisited) = parallel_ssa_cyclic(f);
if unvisited.contains(&1) {
Err(SSAError::Cycle)
} else {
Ok(result)
}
}
pub fn parallel_ssa_cyclic<O: Clone, A: Clone>(
f: strict::OpenHypergraph<VecKind, O, A>,
) -> (Vec<Vec<SSA<O, A>>>, Vec<usize>) {
let (op_order, unvisited) = strict::layer::layered_operations(&f);
let f = lax::OpenHypergraph::from_strict(f);
let result = op_order
.iter()
.map(|layer| {
layer
.0
.iter()
.map(|edge_id| {
let lax::Hyperedge { sources, targets } =
f.hypergraph.adjacency[*edge_id].clone();
let op = f.hypergraph.edges[*edge_id].clone();
SSA {
op,
edge_id: lax::EdgeId(*edge_id),
sources: sources
.iter()
.map(|id| (*id, f.hypergraph.nodes[id.0].clone()))
.collect(),
targets: targets
.iter()
.map(|id| (*id, f.hypergraph.nodes[id.0].clone()))
.collect(),
}
})
.collect()
})
.collect();
(result, unvisited.0)
}
pub fn ssa<O: Clone, A: Clone>(
f: strict::OpenHypergraph<VecKind, O, A>,
) -> Result<Vec<SSA<O, A>>, SSAError> {
parallel_ssa(f).map(|v| v.into_iter().flatten().collect())
}
impl<O: Debug, A: Debug> Display for SSA<O, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let target_strs: Vec<String> = self
.targets
.iter()
.map(|(node_id, _type)| format!("v{}", node_id.0))
.collect();
let source_strs: Vec<String> = self
.sources
.iter()
.map(|(node_id, _type)| format!("v{}", node_id.0))
.collect();
write!(
f,
"{}:\t{} = {:?}({})",
self.edge_id.0,
target_strs.join(", "),
self.op,
source_strs.join(", ")
)
}
}
#[cfg(test)]
mod tests;