]>
Commit | Line | Data |
---|---|---|
f9f354fc | 1 | use rustc_index::bit_set::BitSet; |
29967ef6 | 2 | use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; |
1b1a35ee | 3 | use rustc_middle::ty::TyCtxt; |
f9f354fc XL |
4 | use std::ops::RangeInclusive; |
5 | ||
6 | use super::visitor::{ResultsVisitable, ResultsVisitor}; | |
a2a8927a XL |
7 | use super::{ |
8 | Analysis, CallReturnPlaces, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget, | |
9 | }; | |
f9f354fc XL |
10 | |
11 | pub trait Direction { | |
923072b8 | 12 | const IS_FORWARD: bool; |
f9f354fc | 13 | |
923072b8 | 14 | const IS_BACKWARD: bool = !Self::IS_FORWARD; |
f9f354fc XL |
15 | |
16 | /// Applies all effects between the given `EffectIndex`s. | |
17 | /// | |
18 | /// `effects.start()` must precede or equal `effects.end()` in this direction. | |
a2a8927a | 19 | fn apply_effects_in_range<'tcx, A>( |
f9f354fc | 20 | analysis: &A, |
1b1a35ee | 21 | state: &mut A::Domain, |
f9f354fc XL |
22 | block: BasicBlock, |
23 | block_data: &mir::BasicBlockData<'tcx>, | |
24 | effects: RangeInclusive<EffectIndex>, | |
25 | ) where | |
26 | A: Analysis<'tcx>; | |
27 | ||
a2a8927a | 28 | fn apply_effects_in_block<'tcx, A>( |
f9f354fc | 29 | analysis: &A, |
1b1a35ee | 30 | state: &mut A::Domain, |
f9f354fc XL |
31 | block: BasicBlock, |
32 | block_data: &mir::BasicBlockData<'tcx>, | |
33 | ) where | |
34 | A: Analysis<'tcx>; | |
35 | ||
a2a8927a | 36 | fn gen_kill_effects_in_block<'tcx, A>( |
f9f354fc XL |
37 | analysis: &A, |
38 | trans: &mut GenKillSet<A::Idx>, | |
39 | block: BasicBlock, | |
40 | block_data: &mir::BasicBlockData<'tcx>, | |
41 | ) where | |
42 | A: GenKillAnalysis<'tcx>; | |
43 | ||
a2a8927a | 44 | fn visit_results_in_block<'mir, 'tcx, F, R>( |
f9f354fc XL |
45 | state: &mut F, |
46 | block: BasicBlock, | |
47 | block_data: &'mir mir::BasicBlockData<'tcx>, | |
48 | results: &R, | |
49 | vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, | |
50 | ) where | |
51 | R: ResultsVisitable<'tcx, FlowState = F>; | |
52 | ||
a2a8927a | 53 | fn join_state_into_successors_of<'tcx, A>( |
f9f354fc XL |
54 | analysis: &A, |
55 | tcx: TyCtxt<'tcx>, | |
56 | body: &mir::Body<'tcx>, | |
57 | dead_unwinds: Option<&BitSet<BasicBlock>>, | |
1b1a35ee | 58 | exit_state: &mut A::Domain, |
f9f354fc | 59 | block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>), |
1b1a35ee | 60 | propagate: impl FnMut(BasicBlock, &A::Domain), |
f9f354fc XL |
61 | ) where |
62 | A: Analysis<'tcx>; | |
63 | } | |
64 | ||
65 | /// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement). | |
66 | pub struct Backward; | |
67 | ||
68 | impl Direction for Backward { | |
923072b8 | 69 | const IS_FORWARD: bool = false; |
f9f354fc | 70 | |
a2a8927a | 71 | fn apply_effects_in_block<'tcx, A>( |
f9f354fc | 72 | analysis: &A, |
1b1a35ee | 73 | state: &mut A::Domain, |
f9f354fc XL |
74 | block: BasicBlock, |
75 | block_data: &mir::BasicBlockData<'tcx>, | |
76 | ) where | |
77 | A: Analysis<'tcx>, | |
78 | { | |
79 | let terminator = block_data.terminator(); | |
80 | let location = Location { block, statement_index: block_data.statements.len() }; | |
81 | analysis.apply_before_terminator_effect(state, terminator, location); | |
82 | analysis.apply_terminator_effect(state, terminator, location); | |
83 | ||
84 | for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { | |
85 | let location = Location { block, statement_index }; | |
86 | analysis.apply_before_statement_effect(state, statement, location); | |
87 | analysis.apply_statement_effect(state, statement, location); | |
88 | } | |
89 | } | |
90 | ||
a2a8927a | 91 | fn gen_kill_effects_in_block<'tcx, A>( |
f9f354fc XL |
92 | analysis: &A, |
93 | trans: &mut GenKillSet<A::Idx>, | |
94 | block: BasicBlock, | |
95 | block_data: &mir::BasicBlockData<'tcx>, | |
96 | ) where | |
97 | A: GenKillAnalysis<'tcx>, | |
98 | { | |
99 | let terminator = block_data.terminator(); | |
100 | let location = Location { block, statement_index: block_data.statements.len() }; | |
101 | analysis.before_terminator_effect(trans, terminator, location); | |
102 | analysis.terminator_effect(trans, terminator, location); | |
103 | ||
104 | for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { | |
105 | let location = Location { block, statement_index }; | |
106 | analysis.before_statement_effect(trans, statement, location); | |
107 | analysis.statement_effect(trans, statement, location); | |
108 | } | |
109 | } | |
110 | ||
a2a8927a | 111 | fn apply_effects_in_range<'tcx, A>( |
f9f354fc | 112 | analysis: &A, |
1b1a35ee | 113 | state: &mut A::Domain, |
f9f354fc XL |
114 | block: BasicBlock, |
115 | block_data: &mir::BasicBlockData<'tcx>, | |
116 | effects: RangeInclusive<EffectIndex>, | |
117 | ) where | |
118 | A: Analysis<'tcx>, | |
119 | { | |
120 | let (from, to) = (*effects.start(), *effects.end()); | |
121 | let terminator_index = block_data.statements.len(); | |
122 | ||
123 | assert!(from.statement_index <= terminator_index); | |
124 | assert!(!to.precedes_in_backward_order(from)); | |
125 | ||
126 | // Handle the statement (or terminator) at `from`. | |
127 | ||
128 | let next_effect = match from.effect { | |
129 | // If we need to apply the terminator effect in all or in part, do so now. | |
130 | _ if from.statement_index == terminator_index => { | |
131 | let location = Location { block, statement_index: from.statement_index }; | |
132 | let terminator = block_data.terminator(); | |
133 | ||
134 | if from.effect == Effect::Before { | |
135 | analysis.apply_before_terminator_effect(state, terminator, location); | |
136 | if to == Effect::Before.at_index(terminator_index) { | |
137 | return; | |
138 | } | |
139 | } | |
140 | ||
141 | analysis.apply_terminator_effect(state, terminator, location); | |
142 | if to == Effect::Primary.at_index(terminator_index) { | |
143 | return; | |
144 | } | |
145 | ||
146 | // If `from.statement_index` is `0`, we will have hit one of the earlier comparisons | |
147 | // with `to`. | |
148 | from.statement_index - 1 | |
149 | } | |
150 | ||
151 | Effect::Primary => { | |
152 | let location = Location { block, statement_index: from.statement_index }; | |
153 | let statement = &block_data.statements[from.statement_index]; | |
154 | ||
155 | analysis.apply_statement_effect(state, statement, location); | |
156 | if to == Effect::Primary.at_index(from.statement_index) { | |
157 | return; | |
158 | } | |
159 | ||
160 | from.statement_index - 1 | |
161 | } | |
162 | ||
163 | Effect::Before => from.statement_index, | |
164 | }; | |
165 | ||
166 | // Handle all statements between `first_unapplied_idx` and `to.statement_index`. | |
167 | ||
168 | for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) { | |
169 | let location = Location { block, statement_index }; | |
170 | let statement = &block_data.statements[statement_index]; | |
171 | analysis.apply_before_statement_effect(state, statement, location); | |
172 | analysis.apply_statement_effect(state, statement, location); | |
173 | } | |
174 | ||
175 | // Handle the statement at `to`. | |
176 | ||
177 | let location = Location { block, statement_index: to.statement_index }; | |
178 | let statement = &block_data.statements[to.statement_index]; | |
179 | analysis.apply_before_statement_effect(state, statement, location); | |
180 | ||
181 | if to.effect == Effect::Before { | |
182 | return; | |
183 | } | |
184 | ||
185 | analysis.apply_statement_effect(state, statement, location); | |
186 | } | |
187 | ||
a2a8927a | 188 | fn visit_results_in_block<'mir, 'tcx, F, R>( |
f9f354fc XL |
189 | state: &mut F, |
190 | block: BasicBlock, | |
191 | block_data: &'mir mir::BasicBlockData<'tcx>, | |
192 | results: &R, | |
193 | vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, | |
194 | ) where | |
195 | R: ResultsVisitable<'tcx, FlowState = F>, | |
196 | { | |
197 | results.reset_to_block_entry(state, block); | |
198 | ||
199 | vis.visit_block_end(&state, block_data, block); | |
200 | ||
201 | // Terminator | |
202 | let loc = Location { block, statement_index: block_data.statements.len() }; | |
203 | let term = block_data.terminator(); | |
204 | results.reconstruct_before_terminator_effect(state, term, loc); | |
205 | vis.visit_terminator_before_primary_effect(state, term, loc); | |
206 | results.reconstruct_terminator_effect(state, term, loc); | |
207 | vis.visit_terminator_after_primary_effect(state, term, loc); | |
208 | ||
209 | for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { | |
210 | let loc = Location { block, statement_index }; | |
211 | results.reconstruct_before_statement_effect(state, stmt, loc); | |
212 | vis.visit_statement_before_primary_effect(state, stmt, loc); | |
213 | results.reconstruct_statement_effect(state, stmt, loc); | |
214 | vis.visit_statement_after_primary_effect(state, stmt, loc); | |
215 | } | |
216 | ||
217 | vis.visit_block_start(state, block_data, block); | |
218 | } | |
219 | ||
a2a8927a | 220 | fn join_state_into_successors_of<'tcx, A>( |
f9f354fc XL |
221 | analysis: &A, |
222 | _tcx: TyCtxt<'tcx>, | |
223 | body: &mir::Body<'tcx>, | |
224 | dead_unwinds: Option<&BitSet<BasicBlock>>, | |
1b1a35ee | 225 | exit_state: &mut A::Domain, |
f9f354fc | 226 | (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), |
1b1a35ee | 227 | mut propagate: impl FnMut(BasicBlock, &A::Domain), |
f9f354fc XL |
228 | ) where |
229 | A: Analysis<'tcx>, | |
230 | { | |
064997fb | 231 | for pred in body.basic_blocks.predecessors()[bb].iter().copied() { |
f9f354fc XL |
232 | match body[pred].terminator().kind { |
233 | // Apply terminator-specific edge effects. | |
234 | // | |
235 | // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally. | |
923072b8 | 236 | mir::TerminatorKind::Call { destination, target: Some(dest), .. } if dest == bb => { |
a2a8927a XL |
237 | let mut tmp = exit_state.clone(); |
238 | analysis.apply_call_return_effect( | |
239 | &mut tmp, | |
240 | pred, | |
923072b8 | 241 | CallReturnPlaces::Call(destination), |
a2a8927a XL |
242 | ); |
243 | propagate(pred, &tmp); | |
244 | } | |
5e7ed085 | 245 | |
a2a8927a XL |
246 | mir::TerminatorKind::InlineAsm { |
247 | destination: Some(dest), ref operands, .. | |
f9f354fc XL |
248 | } if dest == bb => { |
249 | let mut tmp = exit_state.clone(); | |
a2a8927a XL |
250 | analysis.apply_call_return_effect( |
251 | &mut tmp, | |
252 | pred, | |
253 | CallReturnPlaces::InlineAsm(operands), | |
254 | ); | |
f9f354fc XL |
255 | propagate(pred, &tmp); |
256 | } | |
257 | ||
258 | mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => { | |
259 | let mut tmp = exit_state.clone(); | |
260 | analysis.apply_yield_resume_effect(&mut tmp, resume, resume_arg); | |
261 | propagate(pred, &tmp); | |
262 | } | |
263 | ||
5e7ed085 FG |
264 | mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => { |
265 | let mut applier = BackwardSwitchIntEdgeEffectsApplier { | |
04454e1e | 266 | body, |
5e7ed085 FG |
267 | pred, |
268 | exit_state, | |
5e7ed085 FG |
269 | bb, |
270 | propagate: &mut propagate, | |
271 | effects_applied: false, | |
272 | }; | |
273 | ||
274 | analysis.apply_switch_int_edge_effects(pred, discr, &mut applier); | |
275 | ||
276 | if !applier.effects_applied { | |
277 | propagate(pred, exit_state) | |
278 | } | |
279 | } | |
280 | ||
f9f354fc XL |
281 | // Ignore dead unwinds. |
282 | mir::TerminatorKind::Call { cleanup: Some(unwind), .. } | |
283 | | mir::TerminatorKind::Assert { cleanup: Some(unwind), .. } | |
284 | | mir::TerminatorKind::Drop { unwind: Some(unwind), .. } | |
285 | | mir::TerminatorKind::DropAndReplace { unwind: Some(unwind), .. } | |
286 | | mir::TerminatorKind::FalseUnwind { unwind: Some(unwind), .. } | |
a2a8927a | 287 | | mir::TerminatorKind::InlineAsm { cleanup: Some(unwind), .. } |
f9f354fc XL |
288 | if unwind == bb => |
289 | { | |
290 | if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { | |
291 | propagate(pred, exit_state); | |
292 | } | |
293 | } | |
294 | ||
295 | _ => propagate(pred, exit_state), | |
296 | } | |
297 | } | |
298 | } | |
299 | } | |
300 | ||
923072b8 FG |
301 | struct BackwardSwitchIntEdgeEffectsApplier<'a, 'tcx, D, F> { |
302 | body: &'a mir::Body<'tcx>, | |
5e7ed085 FG |
303 | pred: BasicBlock, |
304 | exit_state: &'a mut D, | |
5e7ed085 FG |
305 | bb: BasicBlock, |
306 | propagate: &'a mut F, | |
307 | ||
308 | effects_applied: bool, | |
309 | } | |
310 | ||
923072b8 | 311 | impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplier<'_, '_, D, F> |
5e7ed085 FG |
312 | where |
313 | D: Clone, | |
314 | F: FnMut(BasicBlock, &D), | |
315 | { | |
316 | fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { | |
317 | assert!(!self.effects_applied); | |
318 | ||
064997fb | 319 | let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)]; |
04454e1e | 320 | let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); |
5e7ed085 FG |
321 | |
322 | let mut tmp = None; | |
323 | for target in targets { | |
324 | let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); | |
325 | apply_edge_effect(tmp, target); | |
326 | (self.propagate)(self.pred, tmp); | |
327 | } | |
328 | ||
329 | self.effects_applied = true; | |
330 | } | |
331 | } | |
332 | ||
f9f354fc XL |
333 | /// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator). |
334 | pub struct Forward; | |
335 | ||
336 | impl Direction for Forward { | |
923072b8 | 337 | const IS_FORWARD: bool = true; |
f9f354fc | 338 | |
a2a8927a | 339 | fn apply_effects_in_block<'tcx, A>( |
f9f354fc | 340 | analysis: &A, |
1b1a35ee | 341 | state: &mut A::Domain, |
f9f354fc XL |
342 | block: BasicBlock, |
343 | block_data: &mir::BasicBlockData<'tcx>, | |
344 | ) where | |
345 | A: Analysis<'tcx>, | |
346 | { | |
347 | for (statement_index, statement) in block_data.statements.iter().enumerate() { | |
348 | let location = Location { block, statement_index }; | |
349 | analysis.apply_before_statement_effect(state, statement, location); | |
350 | analysis.apply_statement_effect(state, statement, location); | |
351 | } | |
352 | ||
353 | let terminator = block_data.terminator(); | |
354 | let location = Location { block, statement_index: block_data.statements.len() }; | |
355 | analysis.apply_before_terminator_effect(state, terminator, location); | |
356 | analysis.apply_terminator_effect(state, terminator, location); | |
357 | } | |
358 | ||
a2a8927a | 359 | fn gen_kill_effects_in_block<'tcx, A>( |
f9f354fc XL |
360 | analysis: &A, |
361 | trans: &mut GenKillSet<A::Idx>, | |
362 | block: BasicBlock, | |
363 | block_data: &mir::BasicBlockData<'tcx>, | |
364 | ) where | |
365 | A: GenKillAnalysis<'tcx>, | |
366 | { | |
367 | for (statement_index, statement) in block_data.statements.iter().enumerate() { | |
368 | let location = Location { block, statement_index }; | |
369 | analysis.before_statement_effect(trans, statement, location); | |
370 | analysis.statement_effect(trans, statement, location); | |
371 | } | |
372 | ||
373 | let terminator = block_data.terminator(); | |
374 | let location = Location { block, statement_index: block_data.statements.len() }; | |
375 | analysis.before_terminator_effect(trans, terminator, location); | |
376 | analysis.terminator_effect(trans, terminator, location); | |
377 | } | |
378 | ||
a2a8927a | 379 | fn apply_effects_in_range<'tcx, A>( |
f9f354fc | 380 | analysis: &A, |
1b1a35ee | 381 | state: &mut A::Domain, |
f9f354fc XL |
382 | block: BasicBlock, |
383 | block_data: &mir::BasicBlockData<'tcx>, | |
384 | effects: RangeInclusive<EffectIndex>, | |
385 | ) where | |
386 | A: Analysis<'tcx>, | |
387 | { | |
388 | let (from, to) = (*effects.start(), *effects.end()); | |
389 | let terminator_index = block_data.statements.len(); | |
390 | ||
391 | assert!(to.statement_index <= terminator_index); | |
392 | assert!(!to.precedes_in_forward_order(from)); | |
393 | ||
394 | // If we have applied the before affect of the statement or terminator at `from` but not its | |
395 | // after effect, do so now and start the loop below from the next statement. | |
396 | ||
397 | let first_unapplied_index = match from.effect { | |
398 | Effect::Before => from.statement_index, | |
399 | ||
400 | Effect::Primary if from.statement_index == terminator_index => { | |
401 | debug_assert_eq!(from, to); | |
402 | ||
403 | let location = Location { block, statement_index: terminator_index }; | |
404 | let terminator = block_data.terminator(); | |
405 | analysis.apply_terminator_effect(state, terminator, location); | |
406 | return; | |
407 | } | |
408 | ||
409 | Effect::Primary => { | |
410 | let location = Location { block, statement_index: from.statement_index }; | |
411 | let statement = &block_data.statements[from.statement_index]; | |
412 | analysis.apply_statement_effect(state, statement, location); | |
413 | ||
414 | // If we only needed to apply the after effect of the statement at `idx`, we are done. | |
415 | if from == to { | |
416 | return; | |
417 | } | |
418 | ||
419 | from.statement_index + 1 | |
420 | } | |
421 | }; | |
422 | ||
423 | // Handle all statements between `from` and `to` whose effects must be applied in full. | |
424 | ||
425 | for statement_index in first_unapplied_index..to.statement_index { | |
426 | let location = Location { block, statement_index }; | |
427 | let statement = &block_data.statements[statement_index]; | |
428 | analysis.apply_before_statement_effect(state, statement, location); | |
429 | analysis.apply_statement_effect(state, statement, location); | |
430 | } | |
431 | ||
432 | // Handle the statement or terminator at `to`. | |
433 | ||
434 | let location = Location { block, statement_index: to.statement_index }; | |
435 | if to.statement_index == terminator_index { | |
436 | let terminator = block_data.terminator(); | |
437 | analysis.apply_before_terminator_effect(state, terminator, location); | |
438 | ||
439 | if to.effect == Effect::Primary { | |
440 | analysis.apply_terminator_effect(state, terminator, location); | |
441 | } | |
442 | } else { | |
443 | let statement = &block_data.statements[to.statement_index]; | |
444 | analysis.apply_before_statement_effect(state, statement, location); | |
445 | ||
446 | if to.effect == Effect::Primary { | |
447 | analysis.apply_statement_effect(state, statement, location); | |
448 | } | |
449 | } | |
450 | } | |
451 | ||
a2a8927a | 452 | fn visit_results_in_block<'mir, 'tcx, F, R>( |
f9f354fc XL |
453 | state: &mut F, |
454 | block: BasicBlock, | |
455 | block_data: &'mir mir::BasicBlockData<'tcx>, | |
456 | results: &R, | |
457 | vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>, | |
458 | ) where | |
459 | R: ResultsVisitable<'tcx, FlowState = F>, | |
460 | { | |
461 | results.reset_to_block_entry(state, block); | |
462 | ||
463 | vis.visit_block_start(state, block_data, block); | |
464 | ||
465 | for (statement_index, stmt) in block_data.statements.iter().enumerate() { | |
466 | let loc = Location { block, statement_index }; | |
467 | results.reconstruct_before_statement_effect(state, stmt, loc); | |
468 | vis.visit_statement_before_primary_effect(state, stmt, loc); | |
469 | results.reconstruct_statement_effect(state, stmt, loc); | |
470 | vis.visit_statement_after_primary_effect(state, stmt, loc); | |
471 | } | |
472 | ||
473 | let loc = Location { block, statement_index: block_data.statements.len() }; | |
474 | let term = block_data.terminator(); | |
475 | results.reconstruct_before_terminator_effect(state, term, loc); | |
476 | vis.visit_terminator_before_primary_effect(state, term, loc); | |
477 | results.reconstruct_terminator_effect(state, term, loc); | |
478 | vis.visit_terminator_after_primary_effect(state, term, loc); | |
479 | ||
480 | vis.visit_block_end(state, block_data, block); | |
481 | } | |
482 | ||
a2a8927a | 483 | fn join_state_into_successors_of<'tcx, A>( |
f9f354fc | 484 | analysis: &A, |
1b1a35ee XL |
485 | _tcx: TyCtxt<'tcx>, |
486 | _body: &mir::Body<'tcx>, | |
f9f354fc | 487 | dead_unwinds: Option<&BitSet<BasicBlock>>, |
1b1a35ee | 488 | exit_state: &mut A::Domain, |
f9f354fc | 489 | (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), |
1b1a35ee | 490 | mut propagate: impl FnMut(BasicBlock, &A::Domain), |
f9f354fc XL |
491 | ) where |
492 | A: Analysis<'tcx>, | |
493 | { | |
494 | use mir::TerminatorKind::*; | |
495 | match bb_data.terminator().kind { | |
496 | Return | Resume | Abort | GeneratorDrop | Unreachable => {} | |
497 | ||
498 | Goto { target } => propagate(target, exit_state), | |
499 | ||
500 | Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ } | |
f035d41b XL |
501 | | Drop { target, unwind, place: _ } |
502 | | DropAndReplace { target, unwind, value: _, place: _ } | |
f9f354fc XL |
503 | | FalseUnwind { real_target: target, unwind } => { |
504 | if let Some(unwind) = unwind { | |
505 | if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { | |
506 | propagate(unwind, exit_state); | |
507 | } | |
508 | } | |
509 | ||
510 | propagate(target, exit_state); | |
511 | } | |
512 | ||
f035d41b | 513 | FalseEdge { real_target, imaginary_target } => { |
f9f354fc XL |
514 | propagate(real_target, exit_state); |
515 | propagate(imaginary_target, exit_state); | |
516 | } | |
517 | ||
518 | Yield { resume: target, drop, resume_arg, value: _ } => { | |
519 | if let Some(drop) = drop { | |
520 | propagate(drop, exit_state); | |
521 | } | |
522 | ||
523 | analysis.apply_yield_resume_effect(exit_state, target, resume_arg); | |
524 | propagate(target, exit_state); | |
525 | } | |
526 | ||
923072b8 FG |
527 | Call { |
528 | cleanup, | |
529 | destination, | |
530 | target, | |
531 | func: _, | |
532 | args: _, | |
533 | from_hir_call: _, | |
534 | fn_span: _, | |
535 | } => { | |
f9f354fc XL |
536 | if let Some(unwind) = cleanup { |
537 | if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { | |
538 | propagate(unwind, exit_state); | |
539 | } | |
540 | } | |
541 | ||
923072b8 | 542 | if let Some(target) = target { |
f9f354fc XL |
543 | // N.B.: This must be done *last*, otherwise the unwind path will see the call |
544 | // return effect. | |
a2a8927a XL |
545 | analysis.apply_call_return_effect( |
546 | exit_state, | |
547 | bb, | |
923072b8 | 548 | CallReturnPlaces::Call(destination), |
a2a8927a | 549 | ); |
f9f354fc XL |
550 | propagate(target, exit_state); |
551 | } | |
552 | } | |
553 | ||
a2a8927a XL |
554 | InlineAsm { |
555 | template: _, | |
556 | ref operands, | |
557 | options: _, | |
558 | line_spans: _, | |
559 | destination, | |
560 | cleanup, | |
561 | } => { | |
562 | if let Some(unwind) = cleanup { | |
563 | if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { | |
564 | propagate(unwind, exit_state); | |
565 | } | |
566 | } | |
567 | ||
f9f354fc | 568 | if let Some(target) = destination { |
a2a8927a XL |
569 | // N.B.: This must be done *last*, otherwise the unwind path will see the call |
570 | // return effect. | |
571 | analysis.apply_call_return_effect( | |
572 | exit_state, | |
573 | bb, | |
574 | CallReturnPlaces::InlineAsm(operands), | |
575 | ); | |
f9f354fc XL |
576 | propagate(target, exit_state); |
577 | } | |
578 | } | |
579 | ||
29967ef6 | 580 | SwitchInt { ref targets, ref discr, switch_ty: _ } => { |
5e7ed085 | 581 | let mut applier = ForwardSwitchIntEdgeEffectsApplier { |
1b1a35ee | 582 | exit_state, |
29967ef6 | 583 | targets, |
1b1a35ee XL |
584 | propagate, |
585 | effects_applied: false, | |
586 | }; | |
587 | ||
588 | analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); | |
589 | ||
5e7ed085 FG |
590 | let ForwardSwitchIntEdgeEffectsApplier { |
591 | exit_state, | |
592 | mut propagate, | |
593 | effects_applied, | |
594 | .. | |
1b1a35ee XL |
595 | } = applier; |
596 | ||
597 | if !effects_applied { | |
29967ef6 XL |
598 | for target in targets.all_targets() { |
599 | propagate(*target, exit_state); | |
f9f354fc XL |
600 | } |
601 | } | |
602 | } | |
603 | } | |
604 | } | |
605 | } | |
606 | ||
5e7ed085 | 607 | struct ForwardSwitchIntEdgeEffectsApplier<'a, D, F> { |
1b1a35ee | 608 | exit_state: &'a mut D, |
29967ef6 | 609 | targets: &'a SwitchTargets, |
1b1a35ee XL |
610 | propagate: F, |
611 | ||
612 | effects_applied: bool, | |
613 | } | |
614 | ||
5e7ed085 | 615 | impl<D, F> super::SwitchIntEdgeEffects<D> for ForwardSwitchIntEdgeEffectsApplier<'_, D, F> |
1b1a35ee XL |
616 | where |
617 | D: Clone, | |
618 | F: FnMut(BasicBlock, &D), | |
619 | { | |
620 | fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { | |
621 | assert!(!self.effects_applied); | |
622 | ||
623 | let mut tmp = None; | |
29967ef6 | 624 | for (value, target) in self.targets.iter() { |
1b1a35ee XL |
625 | let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); |
626 | apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); | |
627 | (self.propagate)(target, tmp); | |
f9f354fc XL |
628 | } |
629 | ||
1b1a35ee XL |
630 | // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, |
631 | // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. | |
29967ef6 | 632 | let otherwise = self.targets.otherwise(); |
1b1a35ee XL |
633 | apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); |
634 | (self.propagate)(otherwise, self.exit_state); | |
635 | ||
636 | self.effects_applied = true; | |
637 | } | |
638 | } | |
639 | ||
640 | /// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses | |
641 | /// the more efficient `clone_from` if `opt` was `Some`. | |
642 | /// | |
643 | /// Returns a mutable reference to the new clone that resides in `opt`. | |
644 | // | |
645 | // FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the | |
646 | // standard library? | |
a2a8927a | 647 | fn opt_clone_from_or_clone<'a, T: Clone>(opt: &'a mut Option<T>, val: &T) -> &'a mut T { |
1b1a35ee XL |
648 | if opt.is_some() { |
649 | let ret = opt.as_mut().unwrap(); | |
650 | ret.clone_from(val); | |
651 | ret | |
652 | } else { | |
653 | *opt = Some(val.clone()); | |
654 | opt.as_mut().unwrap() | |
f9f354fc XL |
655 | } |
656 | } |