Skip to content

Commit dabcbae

Browse files
authored
Rollup merge of #112236 - cjgillot:interval-kill, r=davidtwco
Simplify computation of killed borrows Follow-up to #111759 Processing the first block manually once makes the pre-order walk simpler.
2 parents fa56e01 + f10aa7d commit dabcbae

File tree

1 file changed

+43
-51
lines changed

1 file changed

+43
-51
lines changed

compiler/rustc_borrowck/src/dataflow.rs

+43-51
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,9 @@ pub struct Borrows<'a, 'tcx> {
125125
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
126126
}
127127

128-
struct StackEntry {
129-
bb: mir::BasicBlock,
130-
lo: usize,
131-
hi: usize,
132-
}
133-
134128
struct OutOfScopePrecomputer<'a, 'tcx> {
135129
visited: BitSet<mir::BasicBlock>,
136-
visit_stack: Vec<StackEntry>,
130+
visit_stack: Vec<mir::BasicBlock>,
137131
body: &'a Body<'tcx>,
138132
regioncx: &'a RegionInferenceContext<'tcx>,
139133
borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
@@ -158,68 +152,66 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
158152
borrow_region: RegionVid,
159153
first_location: Location,
160154
) {
161-
// We visit one BB at a time. The complication is that we may start in the
162-
// middle of the first BB visited (the one containing `first_location`), in which
163-
// case we may have to later on process the first part of that BB if there
164-
// is a path back to its start.
165-
166-
// For visited BBs, we record the index of the first statement processed.
167-
// (In fully processed BBs this index is 0.) Note also that we add BBs to
168-
// `visited` once they are added to `stack`, before they are actually
169-
// processed, because this avoids the need to look them up again on
170-
// completion.
171-
self.visited.insert(first_location.block);
172-
173155
let first_block = first_location.block;
174-
let mut first_lo = first_location.statement_index;
175-
let first_hi = self.body[first_block].statements.len();
156+
let first_bb_data = &self.body.basic_blocks[first_block];
157+
158+
// This is the first block, we only want to visit it from the creation of the borrow at
159+
// `first_location`.
160+
let first_lo = first_location.statement_index;
161+
let first_hi = first_bb_data.statements.len();
162+
163+
if let Some(kill_stmt) = self.regioncx.first_non_contained_inclusive(
164+
borrow_region,
165+
first_block,
166+
first_lo,
167+
first_hi,
168+
) {
169+
let kill_location = Location { block: first_block, statement_index: kill_stmt };
170+
// If region does not contain a point at the location, then add to list and skip
171+
// successor locations.
172+
debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location);
173+
self.borrows_out_of_scope_at_location
174+
.entry(kill_location)
175+
.or_default()
176+
.push(borrow_index);
177+
178+
// The borrow is already dead, there is no need to visit other blocks.
179+
return;
180+
}
176181

177-
self.visit_stack.push(StackEntry { bb: first_block, lo: first_lo, hi: first_hi });
182+
// The borrow is not dead. Add successor BBs to the work list, if necessary.
183+
for succ_bb in first_bb_data.terminator().successors() {
184+
if self.visited.insert(succ_bb) {
185+
self.visit_stack.push(succ_bb);
186+
}
187+
}
178188

179-
'preorder: while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
189+
// We may end up visiting `first_block` again. This is not an issue: we know at this point
190+
// that it does not kill the borrow in the `first_lo..=first_hi` range, so checking the
191+
// `0..first_lo` range and the `0..first_hi` range give the same result.
192+
while let Some(block) = self.visit_stack.pop() {
193+
let bb_data = &self.body[block];
194+
let num_stmts = bb_data.statements.len();
180195
if let Some(kill_stmt) =
181-
self.regioncx.first_non_contained_inclusive(borrow_region, bb, lo, hi)
196+
self.regioncx.first_non_contained_inclusive(borrow_region, block, 0, num_stmts)
182197
{
183-
let kill_location = Location { block: bb, statement_index: kill_stmt };
198+
let kill_location = Location { block, statement_index: kill_stmt };
184199
// If region does not contain a point at the location, then add to list and skip
185200
// successor locations.
186201
debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location);
187202
self.borrows_out_of_scope_at_location
188203
.entry(kill_location)
189204
.or_default()
190205
.push(borrow_index);
191-
continue 'preorder;
192-
}
193206

194-
// If we process the first part of the first basic block (i.e. we encounter that block
195-
// for the second time), we no longer have to visit its successors again.
196-
if bb == first_block && hi != first_hi {
207+
// We killed the borrow, so we do not visit this block's successors.
197208
continue;
198209
}
199210

200211
// Add successor BBs to the work list, if necessary.
201-
let bb_data = &self.body[bb];
202-
debug_assert!(hi == bb_data.statements.len());
203212
for succ_bb in bb_data.terminator().successors() {
204-
if !self.visited.insert(succ_bb) {
205-
if succ_bb == first_block && first_lo > 0 {
206-
// `succ_bb` has been seen before. If it wasn't
207-
// fully processed, add its first part to `stack`
208-
// for processing.
209-
self.visit_stack.push(StackEntry { bb: succ_bb, lo: 0, hi: first_lo - 1 });
210-
211-
// And update this entry with 0, to represent the
212-
// whole BB being processed.
213-
first_lo = 0;
214-
}
215-
} else {
216-
// succ_bb hasn't been seen before. Add it to
217-
// `stack` for processing.
218-
self.visit_stack.push(StackEntry {
219-
bb: succ_bb,
220-
lo: 0,
221-
hi: self.body[succ_bb].statements.len(),
222-
});
213+
if self.visited.insert(succ_bb) {
214+
self.visit_stack.push(succ_bb);
223215
}
224216
}
225217
}

0 commit comments

Comments
 (0)