mod backward;
mod forward;
mod lattice;
use midenc_hir::{
pass::AnalysisManager, Backward, CallOpInterface, Forward, OpOperandImpl, Operation,
ProgramPoint, RegionSuccessor, Report,
};
pub use self::{
backward::{set_all_to_exit_states, SparseBackwardDataFlowAnalysis},
forward::{set_all_to_entry_states, SparseForwardDataFlowAnalysis},
lattice::SparseLattice,
};
use super::{AnalysisStrategy, DataFlowAnalysis, DataFlowSolver, Sparse};
pub struct SparseDataFlowAnalysis<A, D> {
analysis: A,
_direction: core::marker::PhantomData<D>,
}
impl<A: SparseForwardDataFlowAnalysis> AnalysisStrategy<A> for SparseDataFlowAnalysis<A, Forward> {
type Direction = Forward;
type Kind = Sparse;
fn build(analysis: A, _solver: &mut DataFlowSolver) -> Self {
Self {
analysis,
_direction: core::marker::PhantomData,
}
}
}
impl<A: SparseBackwardDataFlowAnalysis> AnalysisStrategy<A>
for SparseDataFlowAnalysis<A, Backward>
{
type Direction = Backward;
type Kind = Sparse;
fn build(analysis: A, _solver: &mut DataFlowSolver) -> Self {
Self {
analysis,
_direction: core::marker::PhantomData,
}
}
}
impl<A: SparseForwardDataFlowAnalysis> DataFlowAnalysis for SparseDataFlowAnalysis<A, Forward> {
fn debug_name(&self) -> &'static str {
self.analysis.debug_name()
}
fn analysis_id(&self) -> core::any::TypeId {
core::any::TypeId::of::<Self>()
}
fn initialize(
&self,
top: &Operation,
solver: &mut DataFlowSolver,
_analysis_manager: AnalysisManager,
) -> Result<(), Report> {
log::trace!(
target: self.analysis.debug_name(),
"initializing analysis for {top}",
);
for region in top.regions() {
if region.is_empty() {
continue;
}
log::trace!(
target: self.analysis.debug_name(),
"initializing entry arguments of region {}",
region.region_number()
);
for argument in region.entry().arguments() {
let argument = argument.borrow().as_value_ref();
let mut lattice = solver.get_or_create_mut::<_, _>(argument);
<A as SparseForwardDataFlowAnalysis>::set_to_entry_state(
&self.analysis,
&mut lattice,
);
}
}
forward::initialize_recursively(self, top, solver)
}
fn visit(&self, point: &ProgramPoint, solver: &mut DataFlowSolver) -> Result<(), Report> {
if !point.is_at_block_start() {
return forward::visit_operation(
self,
&point.prev_operation().unwrap().borrow(),
solver,
);
}
forward::visit_block(self, &point.block().unwrap().borrow(), solver);
Ok(())
}
}
impl<A: SparseBackwardDataFlowAnalysis> DataFlowAnalysis for SparseDataFlowAnalysis<A, Backward> {
fn debug_name(&self) -> &'static str {
self.analysis.debug_name()
}
fn analysis_id(&self) -> core::any::TypeId {
core::any::TypeId::of::<Self>()
}
fn initialize(
&self,
top: &Operation,
solver: &mut DataFlowSolver,
_analysis_manager: AnalysisManager,
) -> Result<(), Report> {
log::trace!(
target: self.analysis.debug_name(),
"initializing analysis for {top}",
);
backward::initialize_recursively(self, top, solver)
}
fn visit(&self, point: &ProgramPoint, solver: &mut DataFlowSolver) -> Result<(), Report> {
if point.is_at_block_start() {
Ok(())
} else {
backward::visit_operation(self, &point.prev_operation().unwrap().borrow(), solver)
}
}
}
impl<A: SparseForwardDataFlowAnalysis> SparseForwardDataFlowAnalysis
for SparseDataFlowAnalysis<A, Forward>
{
type Lattice = <A as SparseForwardDataFlowAnalysis>::Lattice;
fn debug_name(&self) -> &'static str {
<A as SparseForwardDataFlowAnalysis>::debug_name(&self.analysis)
}
fn visit_operation(
&self,
op: &Operation,
operands: &[super::AnalysisStateGuard<'_, Self::Lattice>],
results: &mut [super::AnalysisStateGuardMut<'_, Self::Lattice>],
solver: &mut DataFlowSolver,
) -> Result<(), Report> {
<A as SparseForwardDataFlowAnalysis>::visit_operation(
&self.analysis,
op,
operands,
results,
solver,
)
}
fn set_to_entry_state(&self, lattice: &mut super::AnalysisStateGuardMut<'_, Self::Lattice>) {
<A as SparseForwardDataFlowAnalysis>::set_to_entry_state(&self.analysis, lattice);
}
fn visit_external_call(
&self,
call: &dyn CallOpInterface,
arguments: &[super::AnalysisStateGuard<'_, Self::Lattice>],
results: &mut [super::AnalysisStateGuardMut<'_, Self::Lattice>],
solver: &mut DataFlowSolver,
) {
<A as SparseForwardDataFlowAnalysis>::visit_external_call(
&self.analysis,
call,
arguments,
results,
solver,
);
}
fn visit_non_control_flow_arguments(
&self,
op: &Operation,
successor: &RegionSuccessor<'_>,
arguments: &mut [super::AnalysisStateGuardMut<'_, Self::Lattice>],
first_index: usize,
solver: &mut DataFlowSolver,
) {
<A as SparseForwardDataFlowAnalysis>::visit_non_control_flow_arguments(
&self.analysis,
op,
successor,
arguments,
first_index,
solver,
);
}
}
impl<A: SparseBackwardDataFlowAnalysis> SparseBackwardDataFlowAnalysis
for SparseDataFlowAnalysis<A, Backward>
{
type Lattice = <A as SparseBackwardDataFlowAnalysis>::Lattice;
fn debug_name(&self) -> &'static str {
<A as SparseBackwardDataFlowAnalysis>::debug_name(&self.analysis)
}
fn visit_operation(
&self,
op: &Operation,
operands: &mut [super::AnalysisStateGuardMut<'_, Self::Lattice>],
results: &[super::AnalysisStateGuard<'_, Self::Lattice>],
solver: &mut DataFlowSolver,
) -> Result<(), Report> {
<A as SparseBackwardDataFlowAnalysis>::visit_operation(
&self.analysis,
op,
operands,
results,
solver,
)
}
fn set_to_exit_state(&self, lattice: &mut super::AnalysisStateGuardMut<'_, Self::Lattice>) {
<A as SparseBackwardDataFlowAnalysis>::set_to_exit_state(&self.analysis, lattice);
}
fn visit_call_operand(&self, operand: &OpOperandImpl, solver: &mut DataFlowSolver) {
<A as SparseBackwardDataFlowAnalysis>::visit_call_operand(&self.analysis, operand, solver);
}
fn visit_external_call(
&self,
call: &dyn CallOpInterface,
arguments: &mut [super::AnalysisStateGuardMut<'_, Self::Lattice>],
results: &[super::AnalysisStateGuard<'_, Self::Lattice>],
solver: &mut DataFlowSolver,
) {
<A as SparseBackwardDataFlowAnalysis>::visit_external_call(
&self.analysis,
call,
arguments,
results,
solver,
);
}
fn visit_branch_operand(&self, operand: &OpOperandImpl, solver: &mut DataFlowSolver) {
<A as SparseBackwardDataFlowAnalysis>::visit_branch_operand(
&self.analysis,
operand,
solver,
);
}
}