use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use jingle_sleigh::{GeneralizedVarNode, PcodeOperation, VarNode};
use crate::analysis::cpa::lattice::JoinSemiLattice;
use crate::analysis::cpa::state::{AbstractState, MergeOutcome, Successor};
use crate::analysis::varnode::VarNodeSet;
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct LivenessState {
live: VarNodeSet,
}
impl LivenessState {
#[must_use]
pub fn empty() -> Self {
Self {
live: VarNodeSet::default(),
}
}
#[must_use]
pub fn with_set(live: VarNodeSet) -> Self {
Self { live }
}
pub fn live_varnodes(&self) -> impl Iterator<Item = VarNode> + '_ {
self.live.varnodes()
}
#[must_use]
pub fn is_live(&self, vn: &VarNode) -> bool {
self.live.partial_covers(vn)
}
pub(crate) fn apply_transfer(&self, op: &PcodeOperation) -> Self {
let (reads, kill) = reads_kill(op);
let mut new_live = self.live.clone();
new_live.subtract(&kill);
new_live.union(&reads);
Self { live: new_live }
}
}
pub(crate) fn reads_kill(op: &PcodeOperation) -> (VarNodeSet, VarNodeSet) {
let mut reads = VarNodeSet::default();
let mut kill = VarNodeSet::default();
if matches!(
op,
PcodeOperation::Branch { .. } | PcodeOperation::Fallthrough { .. }
) {
return (reads, kill);
}
match op {
PcodeOperation::Branch { .. } | PcodeOperation::Fallthrough { .. } => {
return (reads, kill);
}
PcodeOperation::CBranch { input1, .. } => {
reads.insert(input1);
return (reads, kill);
}
PcodeOperation::Call {
args, call_info, ..
} => {
for arg in args {
reads.insert(arg);
}
if let Some(call_info) = call_info {
for ele in &call_info.killed_regs {
kill.insert(ele);
}
}
return (reads, kill);
}
_ => {}
}
for input in op
.inputs()
.iter()
.filter(|i| i.space_index() != VarNode::CONST_SPACE_INDEX as usize)
{
match input {
GeneralizedVarNode::Direct(vn) => reads.insert(vn),
GeneralizedVarNode::Indirect(ivn) => reads.insert(ivn.pointer_location()),
}
}
if let Some(GeneralizedVarNode::Direct(vn)) = op.output() {
kill.insert(&vn);
}
(reads, kill)
}
impl Hash for LivenessState {
fn hash<H: Hasher>(&self, state: &mut H) {
let mut vns: Vec<VarNode> = self.live.varnodes().collect();
vns.sort();
vns.hash(state);
}
}
impl Display for LivenessState {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let count = self.live.varnodes().count();
write!(f, "Live({count} vars)")
}
}
impl PartialOrd for LivenessState {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.live.partial_cmp(&other.live)
}
}
impl JoinSemiLattice for LivenessState {
fn join(&mut self, other: &Self) {
self.live.union(&other.live);
}
}
impl AbstractState for LivenessState {
fn merge(&mut self, other: &Self) -> MergeOutcome {
self.merge_join(other)
}
fn stop<'a, T: Iterator<Item = &'a Self>>(&'a self, states: T) -> bool {
self.stop_sep(states)
}
fn transfer<'a, B: Borrow<PcodeOperation>>(&'a self, op: B) -> Successor<'a, Self> {
let (reads, kill) = reads_kill(op.borrow());
let mut new_live = self.live.clone();
new_live.subtract(&kill);
new_live.union(&reads);
std::iter::once(Self { live: new_live }).into()
}
}