use super::*;
pub struct CFAOnewayConditional {
pub cond : CFGNode,
pub body : CFGNode,
pub exit : CFGNode
}
impl CFAOnewayConditional {
pub fn find_first(cfg : &ControlFlowGraph) -> Option<Self> {
for cond in cfg.nodes() {
let Some(cond_succs) = cfg.succs(cond) else { continue };
if (cond_succs.len() != 2) { continue; }
let mut cond_succs = cond_succs.into_iter();
let a = cond_succs.next().unwrap();
let b = cond_succs.next().unwrap();
if (Self::is_valid(cfg, cond, a, b)) {
return Some(Self { cond : cond.clone(), body : a.clone(), exit : b.clone() });
}
if (Self::is_valid(cfg, cond, b, a)) {
return Some(Self { cond : cond.clone(), body : b.clone(), exit : a.clone() });
}
}
None
}
fn is_valid(cfg : &ControlFlowGraph, cond : &CFGNode, body : &CFGNode, exit : &CFGNode) -> bool {
if (cfg.temps().contains(cond.to_succ())) { return false; }
if (cfg.temps().contains(exit.from_pred())) { return false; }
if (! cfg.dominates(cond, body)) { return false; }
if (! cfg.dominates(cond, exit)) { return false; }
if let Some(cond_preds) = cfg.preds(cond) {
for cond_pred in cond_preds {
if (! cfg.dominates(cond_pred, cond)) { return false; }
}
}
let Some(cond_succs) = cfg.succs(cond) else { return false };
if (cond_succs.len() != 2) { return false; }
if (! cond_succs.contains(body)) { return false; }
if (! cond_succs.contains(exit)) { return false; }
let Some(body_preds) = cfg.preds(body) else { return false };
if (body_preds.len() != 1) { return false; }
let Some(body_succs) = cfg.succs(body) else { return false };
if (body_succs.len() != 1) { return false; }
if (! body_succs.contains(exit)) { return false };
true
}
pub(crate) fn insert_needed_node(&mut self, cfg : &mut ControlFlowGraph) -> () {
if (cfg.preds(&self.exit).map(|preds| preds.len()).unwrap_or(0) != 2) {
let temporary = cfg.create_temporary_node();
cfg.insert_node(&temporary, &self.cond, &self.exit);
cfg.insert_node(&temporary, &self.body, &self.exit);
self.exit = (&temporary).into();
}
}
}
impl fmt::Display for CFAOnewayConditional {
fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\x1b[2m->\x1b[0m ")?;
write!(f, "\x1b[95m\x1b[1mif\x1b[0m \x1b[37m\x1b[1m(\x1b[0m ")?;
write!(f, "\x1b[36m{}\x1b[0m", self.cond)?;
write!(f, " \x1b[37m\x1b[1m) {{\x1b[0m ")?;
write!(f, "\x1b[36m{}\x1b[0m", self.body)?;
write!(f, " \x1b[37m\x1b[1m}}\x1b[0m ")?;
write!(f, "\x1b[2m->\x1b[0m ")?;
write!(f, "\x1b[36m{}\x1b[0m", self.exit)?;
Ok(())
}
}