@@ -12,6 +12,16 @@ pub trait Direction {
12
12
13
13
const IS_BACKWARD : bool = !Self :: IS_FORWARD ;
14
14
15
+ fn apply_effects_in_block < ' mir , ' tcx , A > (
16
+ analysis : & mut A ,
17
+ body : & mir:: Body < ' tcx > ,
18
+ state : & mut A :: Domain ,
19
+ block : BasicBlock ,
20
+ block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
21
+ propagate : impl FnMut ( BasicBlock , & A :: Domain ) ,
22
+ ) where
23
+ A : Analysis < ' tcx > ;
24
+
15
25
/// Applies all effects between the given `EffectIndex`s.
16
26
///
17
27
/// `effects.start()` must precede or equal `effects.end()` in this direction.
@@ -24,15 +34,6 @@ pub trait Direction {
24
34
) where
25
35
A : Analysis < ' tcx > ;
26
36
27
- fn apply_effects_in_block < ' mir , ' tcx , A > (
28
- analysis : & mut A ,
29
- state : & mut A :: Domain ,
30
- block : BasicBlock ,
31
- block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
32
- ) -> TerminatorEdges < ' mir , ' tcx >
33
- where
34
- A : Analysis < ' tcx > ;
35
-
36
37
fn visit_results_in_block < ' mir , ' tcx , A > (
37
38
state : & mut A :: Domain ,
38
39
block : BasicBlock ,
@@ -41,16 +42,6 @@ pub trait Direction {
41
42
vis : & mut impl ResultsVisitor < ' mir , ' tcx , A > ,
42
43
) where
43
44
A : Analysis < ' tcx > ;
44
-
45
- fn join_state_into_successors_of < ' tcx , A > (
46
- analysis : & mut A ,
47
- body : & mir:: Body < ' tcx > ,
48
- exit_state : & mut A :: Domain ,
49
- block : BasicBlock ,
50
- edges : TerminatorEdges < ' _ , ' tcx > ,
51
- propagate : impl FnMut ( BasicBlock , & A :: Domain ) ,
52
- ) where
53
- A : Analysis < ' tcx > ;
54
45
}
55
46
56
47
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
@@ -61,23 +52,84 @@ impl Direction for Backward {
61
52
62
53
fn apply_effects_in_block < ' mir , ' tcx , A > (
63
54
analysis : & mut A ,
55
+ body : & mir:: Body < ' tcx > ,
64
56
state : & mut A :: Domain ,
65
57
block : BasicBlock ,
66
58
block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
67
- ) -> TerminatorEdges < ' mir , ' tcx >
68
- where
59
+ mut propagate : impl FnMut ( BasicBlock , & A :: Domain ) ,
60
+ ) where
69
61
A : Analysis < ' tcx > ,
70
62
{
71
63
let terminator = block_data. terminator ( ) ;
72
64
let location = Location { block, statement_index : block_data. statements . len ( ) } ;
73
65
analysis. apply_before_terminator_effect ( state, terminator, location) ;
74
- let edges = analysis. apply_terminator_effect ( state, terminator, location) ;
66
+ analysis. apply_terminator_effect ( state, terminator, location) ;
75
67
for ( statement_index, statement) in block_data. statements . iter ( ) . enumerate ( ) . rev ( ) {
76
68
let location = Location { block, statement_index } ;
77
69
analysis. apply_before_statement_effect ( state, statement, location) ;
78
70
analysis. apply_statement_effect ( state, statement, location) ;
79
71
}
80
- edges
72
+
73
+ let exit_state = state;
74
+ for pred in body. basic_blocks . predecessors ( ) [ block] . iter ( ) . copied ( ) {
75
+ match body[ pred] . terminator ( ) . kind {
76
+ // Apply terminator-specific edge effects.
77
+ //
78
+ // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
79
+ mir:: TerminatorKind :: Call { destination, target : Some ( dest) , .. }
80
+ if dest == block =>
81
+ {
82
+ let mut tmp = exit_state. clone ( ) ;
83
+ analysis. apply_call_return_effect (
84
+ & mut tmp,
85
+ pred,
86
+ CallReturnPlaces :: Call ( destination) ,
87
+ ) ;
88
+ propagate ( pred, & tmp) ;
89
+ }
90
+
91
+ mir:: TerminatorKind :: InlineAsm { ref targets, ref operands, .. }
92
+ if targets. contains ( & block) =>
93
+ {
94
+ let mut tmp = exit_state. clone ( ) ;
95
+ analysis. apply_call_return_effect (
96
+ & mut tmp,
97
+ pred,
98
+ CallReturnPlaces :: InlineAsm ( operands) ,
99
+ ) ;
100
+ propagate ( pred, & tmp) ;
101
+ }
102
+
103
+ mir:: TerminatorKind :: Yield { resume, resume_arg, .. } if resume == block => {
104
+ let mut tmp = exit_state. clone ( ) ;
105
+ analysis. apply_call_return_effect (
106
+ & mut tmp,
107
+ resume,
108
+ CallReturnPlaces :: Yield ( resume_arg) ,
109
+ ) ;
110
+ propagate ( pred, & tmp) ;
111
+ }
112
+
113
+ mir:: TerminatorKind :: SwitchInt { targets : _, ref discr } => {
114
+ let mut applier = BackwardSwitchIntEdgeEffectsApplier {
115
+ body,
116
+ pred,
117
+ exit_state,
118
+ block,
119
+ propagate : & mut propagate,
120
+ effects_applied : false ,
121
+ } ;
122
+
123
+ analysis. apply_switch_int_edge_effects ( pred, discr, & mut applier) ;
124
+
125
+ if !applier. effects_applied {
126
+ propagate ( pred, exit_state)
127
+ }
128
+ }
129
+
130
+ _ => propagate ( pred, exit_state) ,
131
+ }
132
+ }
81
133
}
82
134
83
135
fn apply_effects_in_range < ' tcx , A > (
@@ -188,82 +240,13 @@ impl Direction for Backward {
188
240
189
241
vis. visit_block_start ( state) ;
190
242
}
191
-
192
- fn join_state_into_successors_of < ' tcx , A > (
193
- analysis : & mut A ,
194
- body : & mir:: Body < ' tcx > ,
195
- exit_state : & mut A :: Domain ,
196
- bb : BasicBlock ,
197
- _edges : TerminatorEdges < ' _ , ' tcx > ,
198
- mut propagate : impl FnMut ( BasicBlock , & A :: Domain ) ,
199
- ) where
200
- A : Analysis < ' tcx > ,
201
- {
202
- for pred in body. basic_blocks . predecessors ( ) [ bb] . iter ( ) . copied ( ) {
203
- match body[ pred] . terminator ( ) . kind {
204
- // Apply terminator-specific edge effects.
205
- //
206
- // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
207
- mir:: TerminatorKind :: Call { destination, target : Some ( dest) , .. } if dest == bb => {
208
- let mut tmp = exit_state. clone ( ) ;
209
- analysis. apply_call_return_effect (
210
- & mut tmp,
211
- pred,
212
- CallReturnPlaces :: Call ( destination) ,
213
- ) ;
214
- propagate ( pred, & tmp) ;
215
- }
216
-
217
- mir:: TerminatorKind :: InlineAsm { ref targets, ref operands, .. }
218
- if targets. contains ( & bb) =>
219
- {
220
- let mut tmp = exit_state. clone ( ) ;
221
- analysis. apply_call_return_effect (
222
- & mut tmp,
223
- pred,
224
- CallReturnPlaces :: InlineAsm ( operands) ,
225
- ) ;
226
- propagate ( pred, & tmp) ;
227
- }
228
-
229
- mir:: TerminatorKind :: Yield { resume, resume_arg, .. } if resume == bb => {
230
- let mut tmp = exit_state. clone ( ) ;
231
- analysis. apply_call_return_effect (
232
- & mut tmp,
233
- resume,
234
- CallReturnPlaces :: Yield ( resume_arg) ,
235
- ) ;
236
- propagate ( pred, & tmp) ;
237
- }
238
-
239
- mir:: TerminatorKind :: SwitchInt { targets : _, ref discr } => {
240
- let mut applier = BackwardSwitchIntEdgeEffectsApplier {
241
- body,
242
- pred,
243
- exit_state,
244
- bb,
245
- propagate : & mut propagate,
246
- effects_applied : false ,
247
- } ;
248
-
249
- analysis. apply_switch_int_edge_effects ( pred, discr, & mut applier) ;
250
-
251
- if !applier. effects_applied {
252
- propagate ( pred, exit_state)
253
- }
254
- }
255
-
256
- _ => propagate ( pred, exit_state) ,
257
- }
258
- }
259
- }
260
243
}
261
244
262
245
struct BackwardSwitchIntEdgeEffectsApplier < ' mir , ' tcx , D , F > {
263
246
body : & ' mir mir:: Body < ' tcx > ,
264
247
pred : BasicBlock ,
265
248
exit_state : & ' mir mut D ,
266
- bb : BasicBlock ,
249
+ block : BasicBlock ,
267
250
propagate : & ' mir mut F ,
268
251
effects_applied : bool ,
269
252
}
@@ -276,8 +259,8 @@ where
276
259
fn apply ( & mut self , mut apply_edge_effect : impl FnMut ( & mut D , SwitchIntTarget ) ) {
277
260
assert ! ( !self . effects_applied) ;
278
261
279
- let values = & self . body . basic_blocks . switch_sources ( ) [ & ( self . bb , self . pred ) ] ;
280
- let targets = values. iter ( ) . map ( |& value| SwitchIntTarget { value, target : self . bb } ) ;
262
+ let values = & self . body . basic_blocks . switch_sources ( ) [ & ( self . block , self . pred ) ] ;
263
+ let targets = values. iter ( ) . map ( |& value| SwitchIntTarget { value, target : self . block } ) ;
281
264
282
265
let mut tmp = None ;
283
266
for target in targets {
@@ -298,11 +281,12 @@ impl Direction for Forward {
298
281
299
282
fn apply_effects_in_block < ' mir , ' tcx , A > (
300
283
analysis : & mut A ,
284
+ _body : & mir:: Body < ' tcx > ,
301
285
state : & mut A :: Domain ,
302
286
block : BasicBlock ,
303
287
block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
304
- ) -> TerminatorEdges < ' mir , ' tcx >
305
- where
288
+ mut propagate : impl FnMut ( BasicBlock , & A :: Domain ) ,
289
+ ) where
306
290
A : Analysis < ' tcx > ,
307
291
{
308
292
for ( statement_index, statement) in block_data. statements . iter ( ) . enumerate ( ) {
@@ -313,7 +297,53 @@ impl Direction for Forward {
313
297
let terminator = block_data. terminator ( ) ;
314
298
let location = Location { block, statement_index : block_data. statements . len ( ) } ;
315
299
analysis. apply_before_terminator_effect ( state, terminator, location) ;
316
- analysis. apply_terminator_effect ( state, terminator, location)
300
+ let edges = analysis. apply_terminator_effect ( state, terminator, location) ;
301
+
302
+ let exit_state = state;
303
+ match edges {
304
+ TerminatorEdges :: None => { }
305
+ TerminatorEdges :: Single ( target) => propagate ( target, exit_state) ,
306
+ TerminatorEdges :: Double ( target, unwind) => {
307
+ propagate ( target, exit_state) ;
308
+ propagate ( unwind, exit_state) ;
309
+ }
310
+ TerminatorEdges :: AssignOnReturn { return_, cleanup, place } => {
311
+ // This must be done *first*, otherwise the unwind path will see the assignments.
312
+ if let Some ( cleanup) = cleanup {
313
+ propagate ( cleanup, exit_state) ;
314
+ }
315
+
316
+ if !return_. is_empty ( ) {
317
+ analysis. apply_call_return_effect ( exit_state, block, place) ;
318
+ for & target in return_ {
319
+ propagate ( target, exit_state) ;
320
+ }
321
+ }
322
+ }
323
+ TerminatorEdges :: SwitchInt { targets, discr } => {
324
+ let mut applier = ForwardSwitchIntEdgeEffectsApplier {
325
+ exit_state,
326
+ targets,
327
+ propagate,
328
+ effects_applied : false ,
329
+ } ;
330
+
331
+ analysis. apply_switch_int_edge_effects ( block, discr, & mut applier) ;
332
+
333
+ let ForwardSwitchIntEdgeEffectsApplier {
334
+ exit_state,
335
+ mut propagate,
336
+ effects_applied,
337
+ ..
338
+ } = applier;
339
+
340
+ if !effects_applied {
341
+ for target in targets. all_targets ( ) {
342
+ propagate ( * target, exit_state) ;
343
+ }
344
+ }
345
+ }
346
+ }
317
347
}
318
348
319
349
fn apply_effects_in_range < ' tcx , A > (
@@ -351,7 +381,8 @@ impl Direction for Forward {
351
381
let statement = & block_data. statements [ from. statement_index ] ;
352
382
analysis. apply_statement_effect ( state, statement, location) ;
353
383
354
- // If we only needed to apply the after effect of the statement at `idx`, we are done.
384
+ // If we only needed to apply the after effect of the statement at `idx`, we are
385
+ // done.
355
386
if from == to {
356
387
return ;
357
388
}
@@ -419,62 +450,6 @@ impl Direction for Forward {
419
450
420
451
vis. visit_block_end ( state) ;
421
452
}
422
-
423
- fn join_state_into_successors_of < ' tcx , A > (
424
- analysis : & mut A ,
425
- _body : & mir:: Body < ' tcx > ,
426
- exit_state : & mut A :: Domain ,
427
- bb : BasicBlock ,
428
- edges : TerminatorEdges < ' _ , ' tcx > ,
429
- mut propagate : impl FnMut ( BasicBlock , & A :: Domain ) ,
430
- ) where
431
- A : Analysis < ' tcx > ,
432
- {
433
- match edges {
434
- TerminatorEdges :: None => { }
435
- TerminatorEdges :: Single ( target) => propagate ( target, exit_state) ,
436
- TerminatorEdges :: Double ( target, unwind) => {
437
- propagate ( target, exit_state) ;
438
- propagate ( unwind, exit_state) ;
439
- }
440
- TerminatorEdges :: AssignOnReturn { return_, cleanup, place } => {
441
- // This must be done *first*, otherwise the unwind path will see the assignments.
442
- if let Some ( cleanup) = cleanup {
443
- propagate ( cleanup, exit_state) ;
444
- }
445
-
446
- if !return_. is_empty ( ) {
447
- analysis. apply_call_return_effect ( exit_state, bb, place) ;
448
- for & target in return_ {
449
- propagate ( target, exit_state) ;
450
- }
451
- }
452
- }
453
- TerminatorEdges :: SwitchInt { targets, discr } => {
454
- let mut applier = ForwardSwitchIntEdgeEffectsApplier {
455
- exit_state,
456
- targets,
457
- propagate,
458
- effects_applied : false ,
459
- } ;
460
-
461
- analysis. apply_switch_int_edge_effects ( bb, discr, & mut applier) ;
462
-
463
- let ForwardSwitchIntEdgeEffectsApplier {
464
- exit_state,
465
- mut propagate,
466
- effects_applied,
467
- ..
468
- } = applier;
469
-
470
- if !effects_applied {
471
- for target in targets. all_targets ( ) {
472
- propagate ( * target, exit_state) ;
473
- }
474
- }
475
- }
476
- }
477
- }
478
453
}
479
454
480
455
struct ForwardSwitchIntEdgeEffectsApplier < ' mir , D , F > {
0 commit comments