@@ -54,29 +54,72 @@ struct BlockInfo {
54
54
}
55
55
56
56
struct BlockInfoVisitor {
57
- pre_defs : LocalSet ,
58
57
defs : LocalSet ,
59
58
uses : LocalSet ,
60
59
}
61
60
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
+
62
92
impl < ' tcx > Visitor < ' tcx > for BlockInfoVisitor {
63
93
fn visit_local ( & mut self ,
64
94
& local: & Local ,
65
95
context : LvalueContext < ' tcx > ,
66
96
_: Location ) {
67
97
match context {
98
+ ///////////////////////////////////////////////////////////////////////////
99
+ // DEFS
100
+
68
101
LvalueContext :: Store |
69
102
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
72
111
LvalueContext :: Call |
73
112
74
113
// Storage live and storage dead aren't proper defines, but we can ignore
75
114
// values that come before them.
76
115
LvalueContext :: StorageLive |
77
116
LvalueContext :: StorageDead => {
78
- self . defs . add ( & local) ;
117
+ self . add_def ( local) ;
79
118
}
119
+
120
+ ///////////////////////////////////////////////////////////////////////////
121
+ // USES
122
+
80
123
LvalueContext :: Projection ( ..) |
81
124
82
125
// Borrows only consider their local used at the point of the borrow.
@@ -93,29 +136,26 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
93
136
// Drop eloboration should be run before this analysis otherwise
94
137
// the results might be too pessimistic.
95
138
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) ;
100
140
}
101
141
}
102
142
}
103
143
}
104
144
105
145
fn block < ' tcx > ( b : & BasicBlockData < ' tcx > , locals : usize ) -> BlockInfo {
106
146
let mut visitor = BlockInfoVisitor {
107
- pre_defs : LocalSet :: new_empty ( locals) ,
108
147
defs : LocalSet :: new_empty ( locals) ,
109
148
uses : LocalSet :: new_empty ( locals) ,
110
149
} ;
111
150
112
151
let dummy_location = Location { block : BasicBlock :: new ( 0 ) , statement_index : 0 } ;
113
152
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 ( ) {
115
157
visitor. visit_statement ( BasicBlock :: new ( 0 ) , statement, dummy_location) ;
116
- visitor. pre_defs . union ( & visitor. defs ) ;
117
158
}
118
- visitor. visit_terminator ( BasicBlock :: new ( 0 ) , b. terminator ( ) , dummy_location) ;
119
159
120
160
BlockInfo {
121
161
defs : visitor. defs ,
0 commit comments