Skip to content

Commit 2f7aa5d

Browse files
committed
account for cycles in dfs, add edges from LocalWithRefs
1 parent d2b84b0 commit 2f7aa5d

File tree

1 file changed

+79
-44
lines changed

1 file changed

+79
-44
lines changed

compiler/rustc_mir_dataflow/src/impls/live_borrows.rs

Lines changed: 79 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
//! * `_5` (Borrow) -> `_4` (Local)
7474
//! * `_6` (LocalWithRefs) -> `_5` (Borrow)
7575
//! * `_7` (LocalWithRefs) -> `_6` (LocalWithRefs)
76-
//! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs) (FIXME this one is currently not being done, but unsafe)
76+
//! * `_8` (LocalWithRefs) -> `_7` (LocalWithRefs)
7777
//!
7878
//! We also have to be careful when dealing with `Terminator`s. Whenever we pass references,
7979
//! pointers or `Local`s with `NodeKind::LocalWithRefs` to a `TerminatorKind::Call` or
@@ -104,7 +104,7 @@
104104
//! * `_7` is a `Local` of kind `LocalWithRefs` so needs to be taken into account in the
105105
//! analyis. It's live from stmt 5 to stmt 9
106106
//! * `_8` is a `Local` of kind `LocalWithRefs`. It's live from 6. to 7.
107-
//! * `_9` is a `Local` of kind `LocalWithRefs` (FIXME this is currently not done, see FIXME above),
107+
//! * `_9` is a `Local` of kind `LocalWithRefs`
108108
//! it's live at 7.
109109
//!
110110
//! 3. Determining which `Local`s are borrowed
@@ -115,7 +115,7 @@
115115
//! `_6` (Borrow) -> `_4` (Local)
116116
//! `_7` (LocalWithRef) -> `_5` (Borrow)
117117
//! `_8` (LocalWithRef) -> `_6` (Borrow)
118-
//! `_9` (LocalWithRef) -> `_8` (LocalWithRef) (FIXME currently not done)
118+
//! `_9` (LocalWithRef) -> `_8` (LocalWithRef)
119119
//! `_7` (LocalWithRef) -> `_10` (Local)
120120
//!
121121
//! So at each of those statements we have the following `Local`s that are live due to borrows:
@@ -266,7 +266,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
266266
}
267267
StatementKind::FakeRead(..)
268268
| StatementKind::StorageDead(_)
269-
| StatementKind::StorageLive(_) => {}
269+
| StatementKind::StorageLive(_)
270+
| StatementKind::AscribeUserType(..)
271+
| StatementKind::Deinit(_)
272+
| StatementKind::Coverage(_) => {}
270273
_ => {
271274
self.super_statement(statement, location);
272275
}
@@ -289,7 +292,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
289292
// hence we want to treat them as `NodeKind::Borrow`
290293
// FIXME Are these always Operand::Copy or is Operand::Move also possible for refs/ptrs?
291294
let Some(src_local) = self.current_local else {
292-
bug!("Expected self.current_local to be set with Rvalue::Ref|Rvalue::AddressOf");
295+
bug!("Expected self.current_local to be set when encountering Rvalue");
293296
};
294297

295298
// These are just moves of refs/ptrs, hence `NodeKind::Borrow`.
@@ -344,39 +347,57 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
344347

345348
#[instrument(skip(self), level = "debug")]
346349
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
347-
// Add edges for places that correspond to references or raw pointers
350+
// Add edges for places that correspond to references/raw pointers or nodes of kind `LocalWithRefs`
348351
let place_ty = place.ty(self.local_decls, self.tcx).ty;
349352
debug!(?place_ty);
350353
debug!("current local: {:?}", self.current_local);
351-
match place_ty.kind() {
352-
ty::Ref(..) | ty::RawPtr(..) => match self.current_local {
353-
Some(src_local) => {
354-
// If we haven't created a node for this before, then this must be a
355-
// `NodeKind::LocalWithRefs` as we would have handled the
356-
// other possible assignment case (`NodeKind::Local`) previously in
357-
// `visit_rvalue`.
358-
let src_node_kind = NodeKind::LocalWithRefs(src_local);
359-
let src_node_idx = self.maybe_create_node(src_node_kind);
360-
361-
let borrowed_node_kind = NodeKind::Borrow(place.local);
362-
let node_idx = self.maybe_create_node(borrowed_node_kind);
363-
364-
debug!(
365-
"adding edge from {:?}({:?}) -> {:?}({:?})",
366-
src_node_idx,
367-
self.dep_graph.node(src_node_idx).data,
368-
node_idx,
369-
place.local
370-
);
371-
372-
self.dep_graph.add_edge(src_node_idx, node_idx, ());
354+
355+
match self.current_local {
356+
Some(src_local) => {
357+
match place_ty.kind() {
358+
ty::Ref(..) | ty::RawPtr(..) => {
359+
// If we haven't created a node for this before, then this must be a
360+
// `NodeKind::LocalWithRefs` as we would have handled the
361+
// other possible assignment case (`NodeKind::Local`) previously in
362+
// `visit_rvalue`.
363+
let src_node_kind = NodeKind::LocalWithRefs(src_local);
364+
let src_node_idx = self.maybe_create_node(src_node_kind);
365+
366+
let borrowed_node_kind = NodeKind::Borrow(place.local);
367+
let node_idx = self.maybe_create_node(borrowed_node_kind);
368+
369+
debug!(
370+
"adding edge from {:?}({:?}) -> {:?}({:?})",
371+
src_node_idx,
372+
self.dep_graph.node(src_node_idx).data,
373+
node_idx,
374+
place.local
375+
);
376+
377+
self.dep_graph.add_edge(src_node_idx, node_idx, ());
378+
}
379+
_ => {
380+
if let Some(node_idx) = self.locals_to_node_indexes.get(&place.local) {
381+
// LocalsWithRefs -> LocalWithRefs
382+
383+
let node_idx = *node_idx;
384+
let src_node_kind = NodeKind::LocalWithRefs(src_local);
385+
let src_node_idx = self.maybe_create_node(src_node_kind);
386+
387+
debug!(
388+
"adding edge from {:?}({:?}) -> {:?}({:?})",
389+
src_node_idx,
390+
self.dep_graph.node(src_node_idx).data,
391+
node_idx,
392+
self.dep_graph.node(node_idx).data,
393+
);
394+
395+
self.dep_graph.add_edge(src_node_idx, node_idx, ());
396+
}
397+
}
373398
}
374-
None => {}
375-
},
376-
_ => {
377-
// FIXME I think we probably need to introduce edges here if `place.local`
378-
// corresponds to a `NodeKind::LocalWithRefs`
379399
}
400+
_ => {}
380401
}
381402

382403
self.super_place(place, context, location)
@@ -450,25 +471,33 @@ where
450471
dep_graph: &'a Graph<NodeKind, ()>,
451472
) -> FxHashMap<Local, Vec<Local>> {
452473
let mut borrows_to_locals: FxHashMap<Local, Vec<Local>> = Default::default();
474+
let mut locals_visited = vec![];
475+
453476
for (node_idx, node) in dep_graph.enumerated_nodes() {
454477
let current_local = node.data.get_local();
455478
if borrows_to_locals.get(&current_local).is_none() {
456-
Self::dfs_for_node(node_idx, &mut borrows_to_locals, dep_graph);
479+
Self::dfs_for_node(
480+
node_idx,
481+
&mut borrows_to_locals,
482+
dep_graph,
483+
&mut locals_visited,
484+
);
457485
}
458486
}
459487

460488
debug!("borrows_to_locals: {:#?}", borrows_to_locals);
461489
borrows_to_locals
462490
}
463491

464-
// FIXME Account for cycles in the graph!
465492
fn dfs_for_node(
466493
node_idx: NodeIndex,
467494
borrows_to_locals: &mut FxHashMap<Local, Vec<Local>>,
468495
dep_graph: &Graph<NodeKind, ()>,
496+
locals_visited: &mut Vec<Local>,
469497
) -> Vec<Local> {
470498
let src_node = dep_graph.node(node_idx);
471499
let current_local = src_node.data.get_local();
500+
locals_visited.push(current_local);
472501
if let Some(locals_to_keep_alive) = borrows_to_locals.get(&current_local) {
473502
// already traversed this node
474503
return (*locals_to_keep_alive).clone();
@@ -480,30 +509,36 @@ where
480509
num_succs += 1;
481510
let target_node_idx = edge.target();
482511
let target_node = dep_graph.node(target_node_idx);
512+
let target_local = target_node.data.get_local();
513+
if locals_visited.contains(&target_local) {
514+
continue;
515+
}
483516

484517
debug!(
485518
"edge {:?} ({:?}) -> {:?} ({:?})",
486519
node_idx, src_node.data, target_node_idx, target_node.data,
487520
);
488521

489522
let mut locals_to_keep_alive_for_succ =
490-
Self::dfs_for_node(target_node_idx, borrows_to_locals, dep_graph);
523+
Self::dfs_for_node(target_node_idx, borrows_to_locals, dep_graph, locals_visited);
491524
locals_for_node.append(&mut locals_to_keep_alive_for_succ);
492525
}
493526

494-
if num_succs == 0 {
495-
// base node to keep alive
496-
vec![src_node.data.get_local()]
497-
} else {
498-
if matches!(src_node.data, NodeKind::LocalWithRefs(_)) {
527+
match src_node.data {
528+
NodeKind::Local(_) => {
529+
assert!(num_succs == 0, "Local node with successors");
530+
return vec![src_node.data.get_local()];
531+
}
532+
NodeKind::LocalWithRefs(_) => {
499533
// These are locals that we need to keep alive, but that also contain
500534
// successors in the graph since they contain other references/pointers.
501535
locals_for_node.push(current_local);
502536
}
503-
504-
borrows_to_locals.insert(current_local, locals_for_node.clone());
505-
locals_for_node
537+
NodeKind::Borrow(_) => {}
506538
}
539+
540+
borrows_to_locals.insert(current_local, locals_for_node.clone());
541+
locals_for_node
507542
}
508543
}
509544

0 commit comments

Comments
 (0)