use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::Arc;
use crate::analysis::cfg::CfgState;
use crate::analysis::cpa::lattice::JoinSemiLattice;
use crate::analysis::cpa::residue::liveness_map::LivenessMapReducer;
use crate::analysis::cpa::{ConfigurableProgramAnalysis, RunnableConfigurableProgramAnalysis};
use crate::analysis::linkage::PcodeReverseLinkage;
use crate::analysis::liveness::cpa_state::LivenessCpaState;
use crate::analysis::pcode_store::PcodeStore;
pub mod annotated;
pub mod cpa_state;
pub mod state;
pub use annotated::LivenessAnnotated;
pub use state::LivenessState;
pub struct LivenessAnalysis<N: CfgState, L: PcodeReverseLinkage<N>> {
linkage: Arc<L>,
_phantom: PhantomData<N>,
}
impl<N, L> LivenessAnalysis<N, L>
where
N: CfgState + JoinSemiLattice + Display + PartialOrd + Hash + Eq + 'static,
L: PcodeReverseLinkage<N> + 'static,
{
#[must_use]
pub fn new(linkage: Arc<L>) -> Self {
Self {
linkage,
_phantom: PhantomData,
}
}
pub fn run_from_leaves<'op, T: PcodeStore<'op> + ?Sized>(
&self,
store: &'op T,
) -> HashMap<N, LivenessState>
where
LivenessCpaState<N, L>: 'op,
{
let mut result: HashMap<N, LivenessState> = HashMap::new();
for leaf in self.linkage.leaf_nodes() {
let initial_live = leaf
.concrete_location()
.and_then(|addr| store.get_pcode_op_at(addr))
.map(|op| LivenessState::empty().apply_transfer(op.as_ref()))
.unwrap_or_else(LivenessState::empty);
let initial = LivenessCpaState {
location: leaf,
live: initial_live,
linkage: Arc::clone(&self.linkage),
};
let partial: HashMap<N, LivenessState> = self.run_cpa(initial, store);
for (node, liveness) in partial {
result
.entry(node)
.and_modify(|e| e.join(&liveness))
.or_insert(liveness);
}
}
result
}
}
impl<N, L> ConfigurableProgramAnalysis for LivenessAnalysis<N, L>
where
N: CfgState + JoinSemiLattice + Display + PartialOrd + Hash + Eq + 'static,
L: PcodeReverseLinkage<N> + 'static,
{
type State = LivenessCpaState<N, L>;
type Reducer<'op> = LivenessMapReducer<N, L>;
}