use std::fmt::Debug;
use crate::{
analysis::{
dataflow::lattice::MeetSemiLattice, ControlFlowGraph, SsaBlock, SsaCfg, SsaFunction,
},
utils::graph::{NodeId, Predecessors, RootedGraph, Successors},
};
pub trait DataFlowCfg: Predecessors + Successors {
fn entry(&self) -> NodeId;
fn exits(&self) -> Vec<NodeId>;
fn postorder(&self) -> Vec<NodeId>;
fn reverse_postorder(&self) -> Vec<NodeId>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Forward,
Backward,
}
pub trait DataFlowAnalysis {
type Lattice: MeetSemiLattice;
const DIRECTION: Direction;
fn boundary(&self, ssa: &SsaFunction) -> Self::Lattice;
fn initial(&self, ssa: &SsaFunction) -> Self::Lattice;
fn transfer(
&self,
block_id: usize,
block: &SsaBlock,
input: &Self::Lattice,
ssa: &SsaFunction,
) -> Self::Lattice;
fn finalize(
&mut self,
_in_states: &[Self::Lattice],
_out_states: &[Self::Lattice],
_ssa: &SsaFunction,
) {
}
}
#[derive(Debug, Clone)]
pub struct AnalysisResults<L> {
pub in_states: Vec<L>,
pub out_states: Vec<L>,
}
impl<L: Clone> AnalysisResults<L> {
#[must_use]
pub fn new(in_states: Vec<L>, out_states: Vec<L>) -> Self {
Self {
in_states,
out_states,
}
}
#[must_use]
pub fn in_state(&self, block: usize) -> Option<&L> {
self.in_states.get(block)
}
#[must_use]
pub fn out_state(&self, block: usize) -> Option<&L> {
self.out_states.get(block)
}
#[must_use]
pub fn block_count(&self) -> usize {
self.in_states.len()
}
}
impl DataFlowCfg for ControlFlowGraph<'_> {
fn entry(&self) -> NodeId {
RootedGraph::entry(self)
}
fn exits(&self) -> Vec<NodeId> {
self.exits().to_vec()
}
fn postorder(&self) -> Vec<NodeId> {
self.postorder()
}
fn reverse_postorder(&self) -> Vec<NodeId> {
self.reverse_postorder()
}
}
impl DataFlowCfg for SsaCfg<'_> {
fn entry(&self) -> NodeId {
RootedGraph::entry(self)
}
fn exits(&self) -> Vec<NodeId> {
self.exits()
}
fn postorder(&self) -> Vec<NodeId> {
self.postorder()
}
fn reverse_postorder(&self) -> Vec<NodeId> {
self.reverse_postorder()
}
}