Skip to content

Commit 8aa42ed

Browse files
committed
Auto merge of #61787 - ecstatic-morse:dataflow-split-block-sets, r=pnkfelix
rustc_mir: Hide initial block state when defining transfer functions This PR addresses [this FIXME](https://github.com/rust-lang/rust/blob/2887008e0ce0824be4e0e9562c22ea397b165c97/src/librustc_mir/dataflow/mod.rs#L594-L596). This 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 #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`. Additionally, this PR merges `BitSetOperator` and `InitialFlow` into one trait. Since the value of `InitialFlow` defines the semantics of the `join` operation, there's no reason to have seperate traits for each. We can add a default impl of `join` which branches based on `BOTTOM_VALUE`. This should get optimized away.
2 parents 7e08576 + c8cbd4f commit 8aa42ed

File tree

10 files changed

+275
-406
lines changed

10 files changed

+275
-406
lines changed

src/librustc_data_structures/bit_set.rs

-5
Original file line numberDiff line numberDiff line change
@@ -316,11 +316,6 @@ impl<'a, T: Idx> Iterator for BitIter<'a, T> {
316316
}
317317
}
318318

319-
pub trait BitSetOperator {
320-
/// Combine one bitset into another.
321-
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool;
322-
}
323-
324319
#[inline]
325320
fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
326321
where Op: Fn(Word, Word) -> Word

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

+15-24
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
_ => (),
@@ -83,22 +83,13 @@ impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> {
8383
}
8484
}
8585

86-
impl<'a, 'tcx> BitSetOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
87-
#[inline]
88-
fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
89-
inout_set.union(in_set) // "maybe" means we union effects of both preds
90-
}
91-
}
92-
93-
impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
94-
#[inline]
95-
fn bottom_value() -> bool {
96-
false // bottom = unborrowed
97-
}
86+
impl<'a, 'tcx> BottomValue for HaveBeenBorrowedLocals<'a, 'tcx> {
87+
// bottom = unborrowed
88+
const BOTTOM_VALUE: bool = false;
9889
}
9990

100-
struct BorrowedLocalsVisitor<'b, 'c> {
101-
sets: &'b mut BlockSets<'c, Local>,
91+
struct BorrowedLocalsVisitor<'gk> {
92+
trans: &'gk mut GenKillSet<Local>,
10293
}
10394

10495
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
@@ -117,13 +108,13 @@ fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
117108
})
118109
}
119110

120-
impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
111+
impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
121112
fn visit_rvalue(&mut self,
122113
rvalue: &Rvalue<'tcx>,
123114
location: Location) {
124115
if let Rvalue::Ref(_, _, ref place) = *rvalue {
125116
if let Some(local) = find_local(place) {
126-
self.sets.gen(local);
117+
self.trans.gen(local);
127118
}
128119
}
129120

0 commit comments

Comments
 (0)