|
1 | 1 | use std::ops::RangeInclusive; |
2 | 2 |
|
3 | | -use rustc_middle::mir::{ |
4 | | - self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges, |
5 | | -}; |
| 3 | +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; |
6 | 4 |
|
7 | 5 | use super::visitor::ResultsVisitor; |
8 | 6 | use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget}; |
@@ -115,18 +113,18 @@ impl Direction for Backward { |
115 | 113 | } |
116 | 114 |
|
117 | 115 | mir::TerminatorKind::SwitchInt { targets: _, ref discr } => { |
118 | | - let mut applier = BackwardSwitchIntEdgeEffectsApplier { |
119 | | - body, |
120 | | - pred, |
121 | | - exit_state, |
122 | | - block, |
123 | | - propagate: &mut propagate, |
124 | | - effects_applied: false, |
125 | | - }; |
126 | | - |
127 | | - analysis.apply_switch_int_edge_effects(pred, discr, &mut applier); |
128 | | - |
129 | | - if !applier.effects_applied { |
| 116 | + if let Some(mut data) = analysis.get_switch_int_data(block, discr) { |
| 117 | + let values = &body.basic_blocks.switch_sources()[&(block, pred)]; |
| 118 | + let targets = |
| 119 | + values.iter().map(|&value| SwitchIntTarget { value, target: block }); |
| 120 | + |
| 121 | + let mut tmp = None; |
| 122 | + for target in targets { |
| 123 | + let tmp = opt_clone_from_or_clone(&mut tmp, exit_state); |
| 124 | + analysis.apply_switch_int_edge_effect(&mut data, tmp, target); |
| 125 | + propagate(pred, tmp); |
| 126 | + } |
| 127 | + } else { |
130 | 128 | propagate(pred, exit_state) |
131 | 129 | } |
132 | 130 | } |
@@ -245,37 +243,6 @@ impl Direction for Backward { |
245 | 243 | } |
246 | 244 | } |
247 | 245 |
|
248 | | -struct BackwardSwitchIntEdgeEffectsApplier<'mir, 'tcx, D, F> { |
249 | | - body: &'mir mir::Body<'tcx>, |
250 | | - pred: BasicBlock, |
251 | | - exit_state: &'mir mut D, |
252 | | - block: BasicBlock, |
253 | | - propagate: &'mir mut F, |
254 | | - effects_applied: bool, |
255 | | -} |
256 | | - |
257 | | -impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplier<'_, '_, D, F> |
258 | | -where |
259 | | - D: Clone, |
260 | | - F: FnMut(BasicBlock, &D), |
261 | | -{ |
262 | | - fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { |
263 | | - assert!(!self.effects_applied); |
264 | | - |
265 | | - let values = &self.body.basic_blocks.switch_sources()[&(self.block, self.pred)]; |
266 | | - let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.block }); |
267 | | - |
268 | | - let mut tmp = None; |
269 | | - for target in targets { |
270 | | - let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); |
271 | | - apply_edge_effect(tmp, target); |
272 | | - (self.propagate)(self.pred, tmp); |
273 | | - } |
274 | | - |
275 | | - self.effects_applied = true; |
276 | | - } |
277 | | -} |
278 | | - |
279 | 246 | /// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator). |
280 | 247 | pub struct Forward; |
281 | 248 |
|
@@ -324,23 +291,27 @@ impl Direction for Forward { |
324 | 291 | } |
325 | 292 | } |
326 | 293 | TerminatorEdges::SwitchInt { targets, discr } => { |
327 | | - let mut applier = ForwardSwitchIntEdgeEffectsApplier { |
328 | | - exit_state, |
329 | | - targets, |
330 | | - propagate, |
331 | | - effects_applied: false, |
332 | | - }; |
333 | | - |
334 | | - analysis.apply_switch_int_edge_effects(block, discr, &mut applier); |
335 | | - |
336 | | - let ForwardSwitchIntEdgeEffectsApplier { |
337 | | - exit_state, |
338 | | - mut propagate, |
339 | | - effects_applied, |
340 | | - .. |
341 | | - } = applier; |
342 | | - |
343 | | - if !effects_applied { |
| 294 | + if let Some(mut data) = analysis.get_switch_int_data(block, discr) { |
| 295 | + let mut tmp = None; |
| 296 | + for (value, target) in targets.iter() { |
| 297 | + let tmp = opt_clone_from_or_clone(&mut tmp, exit_state); |
| 298 | + analysis.apply_switch_int_edge_effect(&mut data, tmp, SwitchIntTarget { |
| 299 | + value: Some(value), |
| 300 | + target, |
| 301 | + }); |
| 302 | + propagate(target, tmp); |
| 303 | + } |
| 304 | + |
| 305 | + // Once we get to the final, "otherwise" branch, there is no need to preserve |
| 306 | + // `exit_state`, so pass it directly to `apply_switch_int_edge_effect` to save |
| 307 | + // a clone of the dataflow state. |
| 308 | + let otherwise = targets.otherwise(); |
| 309 | + analysis.apply_switch_int_edge_effect(&mut data, exit_state, SwitchIntTarget { |
| 310 | + value: None, |
| 311 | + target: otherwise, |
| 312 | + }); |
| 313 | + propagate(otherwise, exit_state); |
| 314 | + } else { |
344 | 315 | for target in targets.all_targets() { |
345 | 316 | propagate(*target, exit_state); |
346 | 317 | } |
@@ -455,39 +426,6 @@ impl Direction for Forward { |
455 | 426 | } |
456 | 427 | } |
457 | 428 |
|
458 | | -struct ForwardSwitchIntEdgeEffectsApplier<'mir, D, F> { |
459 | | - exit_state: &'mir mut D, |
460 | | - targets: &'mir SwitchTargets, |
461 | | - propagate: F, |
462 | | - |
463 | | - effects_applied: bool, |
464 | | -} |
465 | | - |
466 | | -impl<D, F> super::SwitchIntEdgeEffects<D> for ForwardSwitchIntEdgeEffectsApplier<'_, D, F> |
467 | | -where |
468 | | - D: Clone, |
469 | | - F: FnMut(BasicBlock, &D), |
470 | | -{ |
471 | | - fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { |
472 | | - assert!(!self.effects_applied); |
473 | | - |
474 | | - let mut tmp = None; |
475 | | - for (value, target) in self.targets.iter() { |
476 | | - let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); |
477 | | - apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); |
478 | | - (self.propagate)(target, tmp); |
479 | | - } |
480 | | - |
481 | | - // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, |
482 | | - // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. |
483 | | - let otherwise = self.targets.otherwise(); |
484 | | - apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); |
485 | | - (self.propagate)(otherwise, self.exit_state); |
486 | | - |
487 | | - self.effects_applied = true; |
488 | | - } |
489 | | -} |
490 | | - |
491 | 429 | /// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses |
492 | 430 | /// the more efficient `clone_from` if `opt` was `Some`. |
493 | 431 | /// |
|
0 commit comments