pub mod prims;
use prims::*;
mod merge;
use crate::cfg::{
ControlFlowGraph,
CFGNode
};
use crate::util::unique_vec::UniqueVec;
use std::fmt;
use llvm_ir::Name;
pub enum CFAPrim {
PreconditionLoop (CFAPreconditionLoop ),
PostconditionLoop (CFAPostconditionLoop ),
OnewayConditional (CFAOnewayConditional ),
OnewayReturnConditional (CFAOnewayReturnConditional ),
TwowayConditional (CFATwowayConditional ),
StatementSequence (CFAStatementSequence )
}
impl CFAPrim {
pub fn find_all(mut cfg : ControlFlowGraph) -> Option<CFAPrims> {
let mut prims = Vec::new();
while (cfg.nodes().len() > 1) {
let mut prim = CFAPrim::find_first(&mut cfg)?;
prim.merge(&mut cfg);
prims.push(prim);
}
Some(CFAPrims {
entry : cfg.entry().clone(),
temps : cfg.temps().clone(),
prims
})
}
pub fn find_first(cfg : &ControlFlowGraph) -> Option<Self> {
if let Some(prim) = CFAPreconditionLoop::find_first(cfg) {
return Some(CFAPrim::PreconditionLoop(prim));
}
if let Some(prim) = CFAPostconditionLoop::find_first(cfg) {
return Some(CFAPrim::PostconditionLoop(prim));
}
if let Some(prim) = CFAOnewayConditional::find_first(cfg) {
return Some(CFAPrim::OnewayConditional(prim));
}
if let Some(prim) = CFAOnewayReturnConditional::find_first(cfg) {
return Some(CFAPrim::OnewayReturnConditional(prim));
}
if let Some(prim) = CFATwowayConditional::find_first(cfg) {
return Some(CFAPrim::TwowayConditional(prim));
}
if let Some(prim) = CFAStatementSequence::find_first(cfg) {
return Some(CFAPrim::StatementSequence(prim));
}
None
}
pub fn entry(&self) -> &CFGNode {
match (self) {
Self::PreconditionLoop (CFAPreconditionLoop { cond, .. }) => cond,
Self::PostconditionLoop (CFAPostconditionLoop { cond, .. }) => cond,
Self::OnewayConditional (CFAOnewayConditional { cond, .. }) => cond,
Self::OnewayReturnConditional (CFAOnewayReturnConditional { cond, .. }) => cond,
Self::TwowayConditional (CFATwowayConditional { cond, .. }) => cond,
Self::StatementSequence (CFAStatementSequence { entry, .. }) => entry
}
}
pub fn exit(&self) -> &CFGNode {
match (self) {
Self::PreconditionLoop (CFAPreconditionLoop { exit, .. }) => exit,
Self::PostconditionLoop (CFAPostconditionLoop { exit, .. }) => exit,
Self::OnewayConditional (CFAOnewayConditional { exit, .. }) => exit,
Self::OnewayReturnConditional (CFAOnewayReturnConditional { exit, .. }) => exit,
Self::TwowayConditional (CFATwowayConditional { exit, .. }) => exit,
Self::StatementSequence (CFAStatementSequence { exit, .. }) => exit
}
}
pub fn nodes(&self) -> Vec<&CFGNode> {
match (self) {
Self::PreconditionLoop (CFAPreconditionLoop { cond, body, exit }) => vec![ cond, body, exit ],
Self::PostconditionLoop (CFAPostconditionLoop { cond, exit }) => vec![ cond, exit ],
Self::OnewayConditional (CFAOnewayConditional { cond, body, exit }) => vec![ cond, body, exit ],
Self::OnewayReturnConditional (CFAOnewayReturnConditional { cond, body, exit }) => vec![ cond, body, exit ],
Self::TwowayConditional (CFATwowayConditional { cond, body_a, body_b, exit }) => vec![ cond, body_a, body_b, exit ],
Self::StatementSequence (CFAStatementSequence { entry, exit }) => vec![ entry, exit ]
}
}
}
pub struct CFAPrims {
entry : CFGNode,
temps : UniqueVec<Name>,
prims : Vec<CFAPrim>
}
impl CFAPrims {
pub fn entry(&self) -> &CFGNode { &self.entry }
pub fn temps(&self) -> &UniqueVec<Name> { &self.temps }
pub fn prims(&self) -> &Vec<CFAPrim> { &self.prims }
}
impl fmt::Display for CFAPrim {
fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
match (self) {
Self::PreconditionLoop (prim) => write!(f, "{}", prim)?,
Self::PostconditionLoop (prim) => write!(f, "{}", prim)?,
Self::OnewayConditional (prim) => write!(f, "{}", prim)?,
Self::OnewayReturnConditional (prim) => write!(f, "{}", prim)?,
Self::TwowayConditional (prim) => write!(f, "{}", prim)?,
Self::StatementSequence (prim) => write!(f, "{}", prim)?
}
Ok(())
}
}
impl fmt::Display for CFAPrims {
fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for prim in &self.prims {
if (first) { first = false; }
else { writeln!(f)?; }
write!(f, "{}", prim)?;
}
Ok(())
}
}