Skip to content

Commit c054186

Browse files
rustc_mir: don't pass on_entry when building transfer functions.
This commit makes `sets.on_entry` inaccessible in `{before_,}{statement,terminator}_effect`. This field was meant to allow implementors of `BitDenotation` to access the initial state for each block (optionally with the effect of all previous statements applied via `accumulates_intrablock_state`) while defining transfer functions. However, the ability to set the initial value for the entry set of each basic block (except for START_BLOCK) no longer exists. As a result, this functionality is mostly useless, and when it *was* used it was used erroneously (see rust-lang#62007). Since `on_entry` is now useless, we can also remove `BlockSets`, which held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a `GenKill` struct. Variables of this type are called `trans` since they represent a transfer function. `GenKill`s are stored contiguously in `AllSets`, which reduces the number of bounds checks and may improve cache performance: one is almost never accessed without the other. Replacing `BlockSets` with `GenKill` allows us to define some new helper functions which streamline dataflow iteration and the dataflow-at-location APIs. Notably, `state_for_location` used a subtle side-effect of the `kill`/`kill_all` setters to apply the transfer function, and could be incorrect if a transfer function depended on effects of previous statements in the block on `gen_set`.
1 parent d4d5d67 commit c054186

File tree

9 files changed

+229
-296
lines changed

9 files changed

+229
-296
lines changed

src/librustc_mir/dataflow/at_location.rs

+23-54
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use rustc::mir::{BasicBlock, Location};
55
use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet};
66

7-
use crate::dataflow::{BitDenotation, BlockSets, DataflowResults};
7+
use crate::dataflow::{BitDenotation, DataflowResults, GenKillSet};
88
use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
99

1010
use std::iter;
@@ -66,8 +66,7 @@ where
6666
{
6767
base_results: DataflowResults<'tcx, BD>,
6868
curr_state: BitSet<BD::Idx>,
69-
stmt_gen: HybridBitSet<BD::Idx>,
70-
stmt_kill: HybridBitSet<BD::Idx>,
69+
stmt_trans: GenKillSet<BD::Idx>,
7170
}
7271

7372
impl<'tcx, BD> FlowAtLocation<'tcx, BD>
@@ -89,19 +88,17 @@ where
8988
where
9089
F: FnMut(BD::Idx),
9190
{
92-
self.stmt_gen.iter().for_each(f)
91+
self.stmt_trans.gen_set.iter().for_each(f)
9392
}
9493

9594
pub fn new(results: DataflowResults<'tcx, BD>) -> Self {
9695
let bits_per_block = results.sets().bits_per_block();
9796
let curr_state = BitSet::new_empty(bits_per_block);
98-
let stmt_gen = HybridBitSet::new_empty(bits_per_block);
99-
let stmt_kill = HybridBitSet::new_empty(bits_per_block);
97+
let stmt_trans = GenKillSet::from_elem(HybridBitSet::new_empty(bits_per_block));
10098
FlowAtLocation {
10199
base_results: results,
102-
curr_state: curr_state,
103-
stmt_gen: stmt_gen,
104-
stmt_kill: stmt_kill,
100+
curr_state,
101+
stmt_trans,
105102
}
106103
}
107104

@@ -127,8 +124,7 @@ where
127124
F: FnOnce(BitIter<'_, BD::Idx>),
128125
{
129126
let mut curr_state = self.curr_state.clone();
130-
curr_state.union(&self.stmt_gen);
131-
curr_state.subtract(&self.stmt_kill);
127+
self.stmt_trans.apply(&mut curr_state);
132128
f(curr_state.iter());
133129
}
134130

@@ -142,68 +138,41 @@ impl<'tcx, BD> FlowsAtLocation for FlowAtLocation<'tcx, BD>
142138
where BD: BitDenotation<'tcx>
143139
{
144140
fn reset_to_entry_of(&mut self, bb: BasicBlock) {
145-
self.curr_state.overwrite(self.base_results.sets().on_entry_set_for(bb.index()));
141+
self.curr_state.overwrite(self.base_results.sets().entry_set_for(bb.index()));
146142
}
147143

148144
fn reset_to_exit_of(&mut self, bb: BasicBlock) {
149145
self.reset_to_entry_of(bb);
150-
self.curr_state.union(self.base_results.sets().gen_set_for(bb.index()));
151-
self.curr_state.subtract(self.base_results.sets().kill_set_for(bb.index()));
146+
let trans = self.base_results.sets().trans_for(bb.index());
147+
trans.apply(&mut self.curr_state)
152148
}
153149

154150
fn reconstruct_statement_effect(&mut self, loc: Location) {
155-
self.stmt_gen.clear();
156-
self.stmt_kill.clear();
157-
{
158-
let mut sets = BlockSets {
159-
on_entry: &mut self.curr_state,
160-
gen_set: &mut self.stmt_gen,
161-
kill_set: &mut self.stmt_kill,
162-
};
163-
self.base_results
164-
.operator()
165-
.before_statement_effect(&mut sets, loc);
166-
}
167-
self.apply_local_effect(loc);
151+
self.stmt_trans.clear();
152+
self.base_results
153+
.operator()
154+
.before_statement_effect(&mut self.stmt_trans, loc);
155+
self.stmt_trans.apply(&mut self.curr_state);
168156

169-
let mut sets = BlockSets {
170-
on_entry: &mut self.curr_state,
171-
gen_set: &mut self.stmt_gen,
172-
kill_set: &mut self.stmt_kill,
173-
};
174157
self.base_results
175158
.operator()
176-
.statement_effect(&mut sets, loc);
159+
.statement_effect(&mut self.stmt_trans, loc);
177160
}
178161

179162
fn reconstruct_terminator_effect(&mut self, loc: Location) {
180-
self.stmt_gen.clear();
181-
self.stmt_kill.clear();
182-
{
183-
let mut sets = BlockSets {
184-
on_entry: &mut self.curr_state,
185-
gen_set: &mut self.stmt_gen,
186-
kill_set: &mut self.stmt_kill,
187-
};
188-
self.base_results
189-
.operator()
190-
.before_terminator_effect(&mut sets, loc);
191-
}
192-
self.apply_local_effect(loc);
163+
self.stmt_trans.clear();
164+
self.base_results
165+
.operator()
166+
.before_terminator_effect(&mut self.stmt_trans, loc);
167+
self.stmt_trans.apply(&mut self.curr_state);
193168

194-
let mut sets = BlockSets {
195-
on_entry: &mut self.curr_state,
196-
gen_set: &mut self.stmt_gen,
197-
kill_set: &mut self.stmt_kill,
198-
};
199169
self.base_results
200170
.operator()
201-
.terminator_effect(&mut sets, loc);
171+
.terminator_effect(&mut self.stmt_trans, loc);
202172
}
203173

204174
fn apply_local_effect(&mut self, _loc: Location) {
205-
self.curr_state.union(&self.stmt_gen);
206-
self.curr_state.subtract(&self.stmt_kill);
175+
self.stmt_trans.apply(&mut self.curr_state)
207176
}
208177
}
209178

src/librustc_mir/dataflow/graphviz.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ where MWF: MirWithFlowState<'tcx>,
170170

171171
write!(w, "<tr>")?;
172172
// Entry
173-
dump_set_for!(on_entry_set_for, interpret_set);
173+
dump_set_for!(entry_set_for, interpret_set);
174174

175175
// MIR statements
176176
write!(w, "<td>")?;
@@ -208,7 +208,7 @@ where MWF: MirWithFlowState<'tcx>,
208208
write!(w, "<tr>")?;
209209

210210
// Entry
211-
let set = flow.sets.on_entry_set_for(i);
211+
let set = flow.sets.entry_set_for(i);
212212
write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string()))?;
213213

214214
// Terminator
@@ -221,13 +221,10 @@ where MWF: MirWithFlowState<'tcx>,
221221
}
222222
write!(w, "</td>")?;
223223

224-
// Gen
225-
let set = flow.sets.gen_set_for(i);
226-
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
227-
228-
// Kill
229-
let set = flow.sets.kill_set_for(i);
230-
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", set)))?;
224+
// Gen/Kill
225+
let trans = flow.sets.trans_for(i);
226+
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.gen_set)))?;
227+
write!(w, "<td>{:?}</td>", dot::escape_html(&format!("{:?}", trans.kill_set)))?;
231228

232229
write!(w, "</tr>")?;
233230

src/librustc_mir/dataflow/impls/borrowed_locals.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub use super::*;
22

33
use rustc::mir::*;
44
use rustc::mir::visit::Visitor;
5-
use crate::dataflow::BitDenotation;
5+
use crate::dataflow::{BitDenotation, GenKillSet};
66

77
/// This calculates if any part of a MIR local could have previously been borrowed.
88
/// This means that once a local has been borrowed, its bit will be set
@@ -33,39 +33,39 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
3333
self.body.local_decls.len()
3434
}
3535

36-
fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
36+
fn start_block_effect(&self, _on_entry: &mut BitSet<Local>) {
3737
// Nothing is borrowed on function entry
3838
}
3939

4040
fn statement_effect(&self,
41-
sets: &mut BlockSets<'_, Local>,
41+
trans: &mut GenKillSet<Local>,
4242
loc: Location) {
4343
let stmt = &self.body[loc.block].statements[loc.statement_index];
4444

4545
BorrowedLocalsVisitor {
46-
sets,
46+
trans,
4747
}.visit_statement(stmt, loc);
4848

4949
// StorageDead invalidates all borrows and raw pointers to a local
5050
match stmt.kind {
51-
StatementKind::StorageDead(l) => sets.kill(l),
51+
StatementKind::StorageDead(l) => trans.kill(l),
5252
_ => (),
5353
}
5454
}
5555

5656
fn terminator_effect(&self,
57-
sets: &mut BlockSets<'_, Local>,
57+
trans: &mut GenKillSet<Local>,
5858
loc: Location) {
5959
let terminator = self.body[loc.block].terminator();
6060
BorrowedLocalsVisitor {
61-
sets,
61+
trans,
6262
}.visit_terminator(terminator, loc);
6363
match &terminator.kind {
6464
// Drop terminators borrows the location
6565
TerminatorKind::Drop { location, .. } |
6666
TerminatorKind::DropAndReplace { location, .. } => {
6767
if let Some(local) = find_local(location) {
68-
sets.gen(local);
68+
trans.gen(local);
6969
}
7070
}
7171
_ => (),
@@ -97,8 +97,8 @@ impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
9797
}
9898
}
9999

100-
struct BorrowedLocalsVisitor<'b, 'c> {
101-
sets: &'b mut BlockSets<'c, Local>,
100+
struct BorrowedLocalsVisitor<'gk> {
101+
trans: &'gk mut GenKillSet<Local>,
102102
}
103103

104104
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
@@ -117,13 +117,13 @@ fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
117117
})
118118
}
119119

120-
impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
120+
impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
121121
fn visit_rvalue(&mut self,
122122
rvalue: &Rvalue<'tcx>,
123123
location: Location) {
124124
if let Rvalue::Ref(_, _, ref place) = *rvalue {
125125
if let Some(local) = find_local(place) {
126-
self.sets.gen(local);
126+
self.trans.gen(local);
127127
}
128128
}
129129

src/librustc_mir/dataflow/impls/borrows.rs

+28-22
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1111

12-
use crate::dataflow::{BitDenotation, BlockSets, InitialFlow};
12+
use crate::dataflow::{BitDenotation, InitialFlow, GenKillSet};
1313
use crate::borrow_check::nll::region_infer::RegionInferenceContext;
1414
use crate::borrow_check::nll::ToRegionVid;
1515
use crate::borrow_check::places_conflict;
@@ -168,7 +168,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
168168
/// Add all borrows to the kill set, if those borrows are out of scope at `location`.
169169
/// That means they went out of a nonlexical scope
170170
fn kill_loans_out_of_scope_at_location(&self,
171-
sets: &mut BlockSets<'_, BorrowIndex>,
171+
trans: &mut GenKillSet<BorrowIndex>,
172172
location: Location) {
173173
// NOTE: The state associated with a given `location`
174174
// reflects the dataflow on entry to the statement.
@@ -182,14 +182,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
182182
// region, then setting that gen-bit will override any
183183
// potential kill introduced here.
184184
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
185-
sets.kill_all(indices);
185+
trans.kill_all(indices);
186186
}
187187
}
188188

189189
/// Kill any borrows that conflict with `place`.
190190
fn kill_borrows_on_place(
191191
&self,
192-
sets: &mut BlockSets<'_, BorrowIndex>,
192+
trans: &mut GenKillSet<BorrowIndex>,
193193
place: &Place<'tcx>
194194
) {
195195
debug!("kill_borrows_on_place: place={:?}", place);
@@ -206,7 +206,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
206206
// local must conflict. This is purely an optimization so we don't have to call
207207
// `places_conflict` for every borrow.
208208
if let Place::Base(PlaceBase::Local(_)) = place {
209-
sets.kill_all(other_borrows_of_local);
209+
trans.kill_all(other_borrows_of_local);
210210
return;
211211
}
212212

@@ -224,7 +224,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
224224
places_conflict::PlaceConflictBias::NoOverlap)
225225
});
226226

227-
sets.kill_all(definitely_conflicting_borrows);
227+
trans.kill_all(definitely_conflicting_borrows);
228228
}
229229
}
230230
}
@@ -236,21 +236,24 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
236236
self.borrow_set.borrows.len() * 2
237237
}
238238

239-
fn start_block_effect(&self, _entry_set: &mut BitSet<BorrowIndex>) {
239+
fn start_block_effect(&self, _entry_set: &mut BitSet<Self::Idx>) {
240240
// no borrows of code region_scopes have been taken prior to
241-
// function execution, so this method has no effect on
242-
// `_sets`.
241+
// function execution, so this method has no effect.
243242
}
244243

245244
fn before_statement_effect(&self,
246-
sets: &mut BlockSets<'_, BorrowIndex>,
245+
trans: &mut GenKillSet<Self::Idx>,
247246
location: Location) {
248-
debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location);
249-
self.kill_loans_out_of_scope_at_location(sets, location);
247+
debug!("Borrows::before_statement_effect trans: {:?} location: {:?}",
248+
trans, location);
249+
self.kill_loans_out_of_scope_at_location(trans, location);
250250
}
251251

252-
fn statement_effect(&self, sets: &mut BlockSets<'_, BorrowIndex>, location: Location) {
253-
debug!("Borrows::statement_effect: sets={:?} location={:?}", sets, location);
252+
fn statement_effect(&self,
253+
trans: &mut GenKillSet<Self::Idx>,
254+
location: Location) {
255+
debug!("Borrows::statement_effect: trans={:?} location={:?}",
256+
trans, location);
254257

255258
let block = &self.body.basic_blocks().get(location.block).unwrap_or_else(|| {
256259
panic!("could not find block at location {:?}", location);
@@ -264,7 +267,7 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
264267
mir::StatementKind::Assign(ref lhs, ref rhs) => {
265268
// Make sure there are no remaining borrows for variables
266269
// that are assigned over.
267-
self.kill_borrows_on_place(sets, lhs);
270+
self.kill_borrows_on_place(trans, lhs);
268271

269272
if let mir::Rvalue::Ref(_, _, ref place) = **rhs {
270273
if place.ignore_borrow(
@@ -278,20 +281,20 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
278281
panic!("could not find BorrowIndex for location {:?}", location);
279282
});
280283

281-
sets.gen(*index);
284+
trans.gen(*index);
282285
}
283286
}
284287

285288
mir::StatementKind::StorageDead(local) => {
286289
// Make sure there are no remaining borrows for locals that
287290
// are gone out of scope.
288-
self.kill_borrows_on_place(sets, &Place::Base(PlaceBase::Local(local)));
291+
self.kill_borrows_on_place(trans, &Place::Base(PlaceBase::Local(local)));
289292
}
290293

291294
mir::StatementKind::InlineAsm(ref asm) => {
292295
for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) {
293296
if !kind.is_indirect && !kind.is_rw {
294-
self.kill_borrows_on_place(sets, output);
297+
self.kill_borrows_on_place(trans, output);
295298
}
296299
}
297300
}
@@ -307,13 +310,16 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> {
307310
}
308311

309312
fn before_terminator_effect(&self,
310-
sets: &mut BlockSets<'_, BorrowIndex>,
313+
trans: &mut GenKillSet<Self::Idx>,
311314
location: Location) {
312-
debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location);
313-
self.kill_loans_out_of_scope_at_location(sets, location);
315+
debug!("Borrows::before_terminator_effect: trans={:?} location={:?}",
316+
trans, location);
317+
self.kill_loans_out_of_scope_at_location(trans, location);
314318
}
315319

316-
fn terminator_effect(&self, _: &mut BlockSets<'_, BorrowIndex>, _: Location) {}
320+
fn terminator_effect(&self,
321+
_: &mut GenKillSet<Self::Idx>,
322+
_: Location) {}
317323

318324
fn propagate_call_return(
319325
&self,

0 commit comments

Comments
 (0)