@@ -47,6 +47,113 @@ use std::io::{self, Write};
47
47
48
48
pub type LocalSet = IdxSetBuf < Local > ;
49
49
50
+ // This gives the result of the liveness analysis at the boundary of basic blocks
51
+ pub struct LivenessResult {
52
+ pub ins : IndexVec < BasicBlock , LocalSet > ,
53
+ pub outs : IndexVec < BasicBlock , LocalSet > ,
54
+ }
55
+
56
+ pub fn liveness_of_locals < ' tcx > ( mir : & Mir < ' tcx > ) -> LivenessResult {
57
+ let locals = mir. local_decls . len ( ) ;
58
+ let def_use: IndexVec < _ , _ > = mir. basic_blocks ( ) . iter ( ) . map ( |b| {
59
+ block ( b, locals)
60
+ } ) . collect ( ) ;
61
+
62
+ let mut ins: IndexVec < _ , _ > = mir. basic_blocks ( )
63
+ . indices ( )
64
+ . map ( |_| LocalSet :: new_empty ( locals) )
65
+ . collect ( ) ;
66
+ let mut outs = ins. clone ( ) ;
67
+
68
+ let mut changed = true ;
69
+ let mut bits = LocalSet :: new_empty ( locals) ;
70
+ while changed {
71
+ changed = false ;
72
+
73
+ for b in mir. basic_blocks ( ) . indices ( ) . rev ( ) {
74
+ // outs[b] = ∪ {ins of successors}
75
+ bits. clear ( ) ;
76
+ for & successor in mir. basic_blocks ( ) [ b] . terminator ( ) . successors ( ) . into_iter ( ) {
77
+ bits. union ( & ins[ successor] ) ;
78
+ }
79
+ outs[ b] . clone_from ( & bits) ;
80
+
81
+ // bits = use ∪ (bits - def)
82
+ def_use[ b] . apply ( & mut bits) ;
83
+
84
+ // update bits on entry and flag if they have changed
85
+ if ins[ b] != bits {
86
+ ins[ b] . clone_from ( & bits) ;
87
+ changed = true ;
88
+ }
89
+ }
90
+ }
91
+
92
+ LivenessResult {
93
+ ins,
94
+ outs,
95
+ }
96
+ }
97
+
98
+ impl LivenessResult {
99
+ /// Walks backwards through the statements/terminator in the given
100
+ /// basic block `block`. At each point within `block`, invokes
101
+ /// the callback `op` with the current location and the set of
102
+ /// variables that are live on entry to that location.
103
+ pub fn simulate_block < ' tcx , OP > ( & self ,
104
+ mir : & Mir < ' tcx > ,
105
+ block : BasicBlock ,
106
+ mut callback : OP )
107
+ where OP : FnMut ( Location , & LocalSet )
108
+ {
109
+ let data = & mir[ block] ;
110
+
111
+ // Get a copy of the bits on exit from the block.
112
+ let mut bits = self . outs [ block] . clone ( ) ;
113
+
114
+ // Start with the maximal statement index -- i.e., right before
115
+ // the terminator executes.
116
+ let mut statement_index = data. statements . len ( ) ;
117
+
118
+ // Compute liveness right before terminator and invoke callback.
119
+ let terminator_location = Location { block, statement_index } ;
120
+ let terminator_defs_uses = self . defs_uses ( mir, terminator_location, & data. terminator ) ;
121
+ terminator_defs_uses. apply ( & mut bits) ;
122
+ callback ( terminator_location, & bits) ;
123
+
124
+ // Compute liveness before each statement (in rev order) and invoke callback.
125
+ for statement in data. statements . iter ( ) . rev ( ) {
126
+ statement_index -= 1 ;
127
+ let statement_location = Location { block, statement_index } ;
128
+ let statement_defs_uses = self . defs_uses ( mir, statement_location, statement) ;
129
+ statement_defs_uses. apply ( & mut bits) ;
130
+ callback ( statement_location, & bits) ;
131
+ }
132
+
133
+ assert_eq ! ( bits, self . ins[ block] ) ;
134
+ }
135
+
136
+ fn defs_uses < ' tcx , V > ( & self ,
137
+ mir : & Mir < ' tcx > ,
138
+ location : Location ,
139
+ thing : & V )
140
+ -> DefsUses
141
+ where V : MirVisitable < ' tcx > ,
142
+ {
143
+ let locals = mir. local_decls . len ( ) ;
144
+ let mut visitor = DefsUses {
145
+ defs : LocalSet :: new_empty ( locals) ,
146
+ uses : LocalSet :: new_empty ( locals) ,
147
+ } ;
148
+
149
+ // Visit the various parts of the basic block in reverse. If we go
150
+ // forward, the logic in `add_def` and `add_use` would be wrong.
151
+ thing. apply ( location, & mut visitor) ;
152
+
153
+ visitor
154
+ }
155
+ }
156
+
50
157
#[ derive( Eq , PartialEq , Clone ) ]
51
158
struct DefsUses {
52
159
defs : LocalSet ,
@@ -159,113 +266,6 @@ fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> DefsUses {
159
266
visitor
160
267
}
161
268
162
- // This gives the result of the liveness analysis at the boundary of basic blocks
163
- pub struct LivenessResult {
164
- pub ins : IndexVec < BasicBlock , LocalSet > ,
165
- pub outs : IndexVec < BasicBlock , LocalSet > ,
166
- }
167
-
168
- pub fn liveness_of_locals < ' tcx > ( mir : & Mir < ' tcx > ) -> LivenessResult {
169
- let locals = mir. local_decls . len ( ) ;
170
- let def_use: IndexVec < _ , _ > = mir. basic_blocks ( ) . iter ( ) . map ( |b| {
171
- block ( b, locals)
172
- } ) . collect ( ) ;
173
-
174
- let mut ins: IndexVec < _ , _ > = mir. basic_blocks ( )
175
- . indices ( )
176
- . map ( |_| LocalSet :: new_empty ( locals) )
177
- . collect ( ) ;
178
- let mut outs = ins. clone ( ) ;
179
-
180
- let mut changed = true ;
181
- let mut bits = LocalSet :: new_empty ( locals) ;
182
- while changed {
183
- changed = false ;
184
-
185
- for b in mir. basic_blocks ( ) . indices ( ) . rev ( ) {
186
- // outs[b] = ∪ {ins of successors}
187
- bits. clear ( ) ;
188
- for & successor in mir. basic_blocks ( ) [ b] . terminator ( ) . successors ( ) . into_iter ( ) {
189
- bits. union ( & ins[ successor] ) ;
190
- }
191
- outs[ b] . clone_from ( & bits) ;
192
-
193
- // bits = use ∪ (bits - def)
194
- def_use[ b] . apply ( & mut bits) ;
195
-
196
- // update bits on entry and flag if they have changed
197
- if ins[ b] != bits {
198
- ins[ b] . clone_from ( & bits) ;
199
- changed = true ;
200
- }
201
- }
202
- }
203
-
204
- LivenessResult {
205
- ins,
206
- outs,
207
- }
208
- }
209
-
210
- impl LivenessResult {
211
- /// Walks backwards through the statements/terminator in the given
212
- /// basic block `block`. At each point within `block`, invokes
213
- /// the callback `op` with the current location and the set of
214
- /// variables that are live on entry to that location.
215
- pub fn simulate_block < ' tcx , OP > ( & self ,
216
- mir : & Mir < ' tcx > ,
217
- block : BasicBlock ,
218
- mut callback : OP )
219
- where OP : FnMut ( Location , & LocalSet )
220
- {
221
- let data = & mir[ block] ;
222
-
223
- // Get a copy of the bits on exit from the block.
224
- let mut bits = self . outs [ block] . clone ( ) ;
225
-
226
- // Start with the maximal statement index -- i.e., right before
227
- // the terminator executes.
228
- let mut statement_index = data. statements . len ( ) ;
229
-
230
- // Compute liveness right before terminator and invoke callback.
231
- let terminator_location = Location { block, statement_index } ;
232
- let terminator_defs_uses = self . defs_uses ( mir, terminator_location, & data. terminator ) ;
233
- terminator_defs_uses. apply ( & mut bits) ;
234
- callback ( terminator_location, & bits) ;
235
-
236
- // Compute liveness before each statement (in rev order) and invoke callback.
237
- for statement in data. statements . iter ( ) . rev ( ) {
238
- statement_index -= 1 ;
239
- let statement_location = Location { block, statement_index } ;
240
- let statement_defs_uses = self . defs_uses ( mir, statement_location, statement) ;
241
- statement_defs_uses. apply ( & mut bits) ;
242
- callback ( statement_location, & bits) ;
243
- }
244
-
245
- assert_eq ! ( bits, self . ins[ block] ) ;
246
- }
247
-
248
- fn defs_uses < ' tcx , V > ( & self ,
249
- mir : & Mir < ' tcx > ,
250
- location : Location ,
251
- thing : & V )
252
- -> DefsUses
253
- where V : MirVisitable < ' tcx > ,
254
- {
255
- let locals = mir. local_decls . len ( ) ;
256
- let mut visitor = DefsUses {
257
- defs : LocalSet :: new_empty ( locals) ,
258
- uses : LocalSet :: new_empty ( locals) ,
259
- } ;
260
-
261
- // Visit the various parts of the basic block in reverse. If we go
262
- // forward, the logic in `add_def` and `add_use` would be wrong.
263
- thing. apply ( location, & mut visitor) ;
264
-
265
- visitor
266
- }
267
- }
268
-
269
269
trait MirVisitable < ' tcx > {
270
270
fn apply < V > ( & self , location : Location , visitor : & mut V )
271
271
where V : Visitor < ' tcx > ;
0 commit comments