Skip to content

Commit 9a47fd2

Browse files
committed
factor out pre_defs field by going backwards
1 parent acc5c43 commit 9a47fd2

File tree

2 files changed

+88
-12
lines changed

2 files changed

+88
-12
lines changed

src/librustc_mir/util/liveness.rs

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,72 @@ struct BlockInfo {
5454
}
5555

5656
struct BlockInfoVisitor {
57-
pre_defs: LocalSet,
5857
defs: LocalSet,
5958
uses: LocalSet,
6059
}
6160

61+
impl BlockInfoVisitor {
62+
fn add_def(&mut self, index: Local) {
63+
// If it was used already in the block, remove that use
64+
// now that we found a definition.
65+
//
66+
// Example:
67+
//
68+
// // Defs = {X}, Uses = {}
69+
// X = 5
70+
// // Defs = {}, Uses = {X}
71+
// use(X)
72+
self.uses.remove(&index);
73+
self.defs.add(&index);
74+
}
75+
76+
fn add_use(&mut self, index: Local) {
77+
// Inverse of above.
78+
//
79+
// Example:
80+
//
81+
// // Defs = {}, Uses = {X}
82+
// use(X)
83+
// // Defs = {X}, Uses = {}
84+
// X = 5
85+
// // Defs = {}, Uses = {X}
86+
// use(X)
87+
self.defs.remove(&index);
88+
self.uses.add(&index);
89+
}
90+
}
91+
6292
impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
6393
fn visit_local(&mut self,
6494
&local: &Local,
6595
context: LvalueContext<'tcx>,
6696
_: Location) {
6797
match context {
98+
///////////////////////////////////////////////////////////////////////////
99+
// DEFS
100+
68101
LvalueContext::Store |
69102

70-
// We let Call defined the result in both the success and unwind cases.
71-
// This may not be right.
103+
// We let Call defined the result in both the success and
104+
// unwind cases. This is not really correct, however it
105+
// does not seem to be observable due to the way that we
106+
// generate MIR. See the test case
107+
// `mir-opt/nll/liveness-call-subtlety.rs`. To do things
108+
// properly, we would apply the def in call only to the
109+
// input from the success path and not the unwind
110+
// path. -nmatsakis
72111
LvalueContext::Call |
73112

74113
// Storage live and storage dead aren't proper defines, but we can ignore
75114
// values that come before them.
76115
LvalueContext::StorageLive |
77116
LvalueContext::StorageDead => {
78-
self.defs.add(&local);
117+
self.add_def(local);
79118
}
119+
120+
///////////////////////////////////////////////////////////////////////////
121+
// USES
122+
80123
LvalueContext::Projection(..) |
81124

82125
// Borrows only consider their local used at the point of the borrow.
@@ -93,29 +136,26 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
93136
// Drop eloboration should be run before this analysis otherwise
94137
// the results might be too pessimistic.
95138
LvalueContext::Drop => {
96-
// Ignore uses which are already defined in this block
97-
if !self.pre_defs.contains(&local) {
98-
self.uses.add(&local);
99-
}
139+
self.add_use(local);
100140
}
101141
}
102142
}
103143
}
104144

105145
fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> BlockInfo {
106146
let mut visitor = BlockInfoVisitor {
107-
pre_defs: LocalSet::new_empty(locals),
108147
defs: LocalSet::new_empty(locals),
109148
uses: LocalSet::new_empty(locals),
110149
};
111150

112151
let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 };
113152

114-
for statement in &b.statements {
153+
// Visit the various parts of the basic block in reverse. If we go
154+
// forward, the logic in `add_def` and `add_use` would be wrong.
155+
visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);
156+
for statement in b.statements.iter().rev() {
115157
visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
116-
visitor.pre_defs.union(&visitor.defs);
117158
}
118-
visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);
119159

120160
BlockInfo {
121161
defs: visitor.defs,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-Znll
12+
13+
#![allow(warnings)]
14+
15+
fn use_x(_: usize) -> bool { true }
16+
17+
fn main() {
18+
let mut x = 22;
19+
loop {
20+
// Key point: `x` not live on entry to this basic block.
21+
x = 55;
22+
if use_x(x) { break; }
23+
}
24+
}
25+
26+
// END RUST SOURCE
27+
// START rustc.node12.nll.0.mir
28+
// | Variables live on entry to the block bb1:
29+
// bb1: {
30+
// _1 = const 55usize;
31+
// StorageLive(_3);
32+
// StorageLive(_4);
33+
// _4 = _1;
34+
// _3 = const use_x(_4) -> bb2;
35+
// }
36+
// END rustc.node12.nll.0.mir

0 commit comments

Comments
 (0)