use std::fmt::Debug;
use crate::{
analysis::{cfg::SsaCfg, dataflow::lattice::MeetSemiLattice},
graph::{NodeId, Predecessors, RootedGraph, Successors},
ir::{block::SsaBlock, function::SsaFunction},
target::Target,
};
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<T: Target> {
type Lattice: MeetSemiLattice;
const DIRECTION: Direction;
fn boundary(&self, ssa: &SsaFunction<T>) -> Self::Lattice;
fn initial(&self, ssa: &SsaFunction<T>) -> Self::Lattice;
fn transfer(
&self,
block_id: usize,
block: &SsaBlock<T>,
input: &Self::Lattice,
ssa: &SsaFunction<T>,
) -> Self::Lattice;
fn finalize(
&mut self,
_in_states: &[Self::Lattice],
_out_states: &[Self::Lattice],
_ssa: &SsaFunction<T>,
) {
}
}
#[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<T: Target> DataFlowCfg for SsaCfg<'_, T> {
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()
}
}