Skip to content

Commit

Permalink
intra function call
Browse files Browse the repository at this point in the history
  • Loading branch information
Medowhill committed Jan 22, 2024
1 parent 19f5ba6 commit bee14ad
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 92 deletions.
28 changes: 19 additions & 9 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@ use etrace::some_or;
use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph};
use rustc_index::Idx;

pub fn transitive_closure<T: Idx + Ord>(
graph: &BTreeMap<T, BTreeSet<T>>,
) -> BTreeMap<T, BTreeSet<T>> {
let len = graph.len();
pub fn transitive_closure<T: Clone + Eq + std::hash::Hash>(
graph: &HashMap<T, HashSet<T>>,
) -> HashMap<T, HashSet<T>> {
let id_to_v: Vec<_> = graph.keys().cloned().collect();
let v_to_id: HashMap<_, _> = id_to_v
.iter()
.cloned()
.enumerate()
.map(|(k, v)| (v, k))
.collect();
let len = id_to_v.len();

let mut reachability = vec![vec![false; len]; len];
for (v, succs) in graph.iter() {
for succ in succs {
reachability[v.index()][succ.index()] = true;
reachability[v_to_id[v]][v_to_id[succ]] = true;
}
}

Expand All @@ -25,20 +32,20 @@ pub fn transitive_closure<T: Idx + Ord>(
}
}

let mut new_graph = BTreeMap::new();
let mut new_graph = HashMap::new();
for (i, reachability) in reachability.iter().enumerate() {
let neighbors = reachability
.iter()
.enumerate()
.filter_map(|(to, is_reachable)| {
if *is_reachable {
Some(T::new(to))
Some(id_to_v[to].clone())
} else {
None
}
})
.collect();
new_graph.insert(T::new(i), neighbors);
new_graph.insert(id_to_v[i].clone(), neighbors);
}
new_graph
}
Expand Down Expand Up @@ -104,9 +111,12 @@ pub fn inverse<T: Clone + Eq + std::hash::Hash>(
map: &HashMap<T, HashSet<T>>,
) -> HashMap<T, HashSet<T>> {
let mut inv: HashMap<_, HashSet<_>> = HashMap::new();
for node in map.keys() {
inv.insert(node.clone(), HashSet::new());
}
for (node, succs) in map {
for succ in succs {
inv.entry(succ.clone()).or_default().insert(node.clone());
inv.get_mut(succ).unwrap().insert(node.clone());
}
}
inv
Expand Down
133 changes: 82 additions & 51 deletions src/relational/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_index::bit_set::BitSet;
use rustc_middle::{
mir::{
interpret::ConstValue, visit::Visitor, BasicBlock, Body, ConstantKind, Local, Location,
Operand, Terminator, TerminatorKind,
Operand, Place, Rvalue, Terminator, TerminatorKind,
},
ty::{AdtKind, Ty, TyCtxt, TyKind, TypeAndMut},
};
Expand All @@ -37,7 +37,7 @@ fn analyze_input(input: Input) -> AnalysisResults {
pub fn analyze(tcx: TyCtxt<'_>) -> AnalysisResults {
let hir = tcx.hir();
let may_aliases = steensgaard::analyze(tcx);
let var_graph = may_aliases.get_alias_graph();
let alias_graph = may_aliases.get_alias_graph();

let func_ids: Vec<_> = hir
.items()
Expand All @@ -50,13 +50,18 @@ pub fn analyze(tcx: TyCtxt<'_>) -> AnalysisResults {
})
.collect();

let _call_graph: HashMap<_, _> = func_ids
let (indirect_assigns, call_graph): (HashMap<_, _>, HashMap<_, _>) = func_ids
.iter()
.map(|def_id| {
let body = tcx.optimized_mir(def_id.to_def_id());
(*def_id, get_callees(*def_id, body, &var_graph, tcx))
let (indirect_assigns, callees) = visit_body(*def_id, body, &alias_graph, tcx);
((*def_id, indirect_assigns), (*def_id, callees))
})
.collect();
.unzip();
let mut reachability = graph::transitive_closure(&call_graph);
for (caller, callees) in &mut reachability {
callees.insert(*caller);
}

let mut functions = HashMap::new();
for local_def_id in func_ids.iter().copied() {
Expand Down Expand Up @@ -104,7 +109,9 @@ pub fn analyze(tcx: TyCtxt<'_>) -> AnalysisResults {
local_tys,
local_ptr_tys,
local_def_id,
may_aliases: &may_aliases,
indirect_assigns: &indirect_assigns,
reachability: &reachability,
alias_graph: &alias_graph,
};
functions.insert(def_id, analyzer.analyze());
}
Expand All @@ -119,14 +126,16 @@ pub struct AnalysisResults {

#[allow(missing_debug_implementations)]
pub struct Analyzer<'tcx, 'a> {
tcx: TyCtxt<'tcx>,
pub tcx: TyCtxt<'tcx>,
body: &'tcx Body<'tcx>,
rpo_map: HashMap<BasicBlock, usize>,
dead_locals: Vec<BitSet<Local>>,
local_tys: Vec<TyStructure>,
local_ptr_tys: HashMap<Local, TyStructure>,
local_def_id: LocalDefId,
may_aliases: &'a steensgaard::AnalysisResults,
indirect_assigns: &'a HashMap<LocalDefId, HashSet<Local>>,
reachability: &'a HashMap<LocalDefId, HashSet<LocalDefId>>,
alias_graph: &'a steensgaard::AliasGraph,
}

impl<'tcx> Analyzer<'tcx, '_> {
Expand Down Expand Up @@ -183,39 +192,47 @@ impl<'tcx> Analyzer<'tcx, '_> {
operand.ty(&self.body.local_decls, self.tcx)
}

pub fn find_may_aliases(&self, local: Local) -> HashSet<(Local, u32)> {
let id = self.may_aliases.local(self.local_def_id, local.as_u32());
let ty = self.may_aliases.var_ty(id);

let mut aliases = HashSet::new();
let mut done = HashSet::new();
let mut remainings = HashSet::new();
remainings.insert((ty.var_ty, 0u32));

while !remainings.is_empty() {
let mut new_remainings = HashSet::new();
for (id, depth) in remainings {
done.insert(id);
for (id1, id2) in &self.may_aliases.vars {
if id != *id2 {
continue;
}
let steensgaard::VarId::Local(f, l) = *id1 else { continue };
if f == self.local_def_id {
aliases.insert((Local::from_u32(l), depth));
}
}
for (v, t) in &self.may_aliases.var_tys {
let steensgaard::VarType::Ref(t) = t else { continue };
if t.var_ty == id && !done.contains(v) {
new_remainings.insert((*v, depth + 1));
}
pub fn resolve_indirect_calls(&self, local: Local) -> HashSet<LocalDefId> {
self.alias_graph
.find_fn_may_aliases(self.local_def_id, local)
}

pub fn locals_invalidated_by_call(&self, callee: LocalDefId) -> HashSet<(Local, usize)> {
self.reachability[&callee]
.iter()
.flat_map(|func| {
self.indirect_assigns[func].iter().flat_map(|local| {
self.alias_graph
.find_may_aliases(*func, *local)
.into_iter()
.filter_map(|alias| {
if alias.function == self.local_def_id {
Some((alias.local, alias.depth))
} else {
None
}
})
})
})
.collect()
}

pub fn find_may_aliases(&self, local: Local) -> HashSet<(Local, usize)> {
self.alias_graph
.find_may_aliases(self.local_def_id, local)
.into_iter()
.filter_map(|alias| {
if alias.function == self.local_def_id {
Some((alias.local, alias.depth))
} else {
None
}
}
remainings = new_remainings;
}
})
.collect()
}

aliases
pub fn def_id_to_string(&self, def_id: DefId) -> String {
self.tcx.def_path(def_id).to_string_no_crate_verbose()
}
}

Expand Down Expand Up @@ -439,22 +456,35 @@ fn get_dead_locals<'tcx>(body: &Body<'tcx>, tcx: TyCtxt<'tcx>) -> Vec<BitSet<Loc
.collect()
}

struct CallVisitor<'tcx, 'a> {
struct BodyVisitor<'tcx, 'a> {
tcx: TyCtxt<'tcx>,
callees: HashSet<LocalDefId>,
current_fn: LocalDefId,
var_graph: &'a steensgaard::AliasGraph,

indirect_assigns: HashSet<Local>,
callees: HashSet<LocalDefId>,
}

impl CallVisitor<'_, '_> {
impl BodyVisitor<'_, '_> {
fn def_id_to_string(&self, def_id: DefId) -> String {
self.tcx.def_path(def_id).to_string_no_crate_verbose()
}
}

impl<'tcx> Visitor<'tcx> for CallVisitor<'tcx, '_> {
impl<'tcx> Visitor<'tcx> for BodyVisitor<'tcx, '_> {
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
if place.is_indirect_first_projection() {
self.indirect_assigns.insert(place.local);
}
self.super_assign(place, rvalue, location);
}

fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
if let TerminatorKind::Call { func, .. } = &terminator.kind {
if let TerminatorKind::Call {
func, destination, ..
} = &terminator.kind
{
assert!(destination.projection.is_empty());
match func {
Operand::Copy(f) | Operand::Move(f) => {
assert!(f.projection.is_empty());
Expand All @@ -479,18 +509,19 @@ impl<'tcx> Visitor<'tcx> for CallVisitor<'tcx, '_> {
}
}

fn get_callees<'tcx>(
fn visit_body<'tcx>(
current_fn: LocalDefId,
body: &Body<'tcx>,
var_graph: &steensgaard::AliasGraph,
alias_graph: &steensgaard::AliasGraph,
tcx: TyCtxt<'tcx>,
) -> HashSet<LocalDefId> {
let mut visitor = CallVisitor {
) -> (HashSet<Local>, HashSet<LocalDefId>) {
let mut visitor = BodyVisitor {
tcx,
callees: HashSet::new(),
current_fn,
var_graph,
var_graph: alias_graph,
indirect_assigns: HashSet::new(),
callees: HashSet::new(),
};
visitor.visit_body(body);
visitor.callees
(visitor.indirect_assigns, visitor.callees)
}
2 changes: 1 addition & 1 deletion src/relational/domains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ impl Graph {
self.nodes[loc.root].obj.project_mut(&loc.projection)
}

pub fn invalidate_deref(&mut self, local: Local, mut depth: u32, opt_id: Option<usize>) {
pub fn invalidate_deref(&mut self, local: Local, mut depth: usize, opt_id: Option<usize>) {
let id = *some_or!(self.locals.get(&local), return);
let mut locs = vec![AbsLoc::new(id, vec![])];
while !locs.is_empty() {
Expand Down
Loading

0 comments on commit bee14ad

Please sign in to comment.