From fbc3cc18bee7fb6dfd39e11521783f00506ca06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 8 May 2022 00:00:00 +0000 Subject: [PATCH 1/2] Avoid constructing switch sources unless necessary Switch sources are used by backward analysis with a custom switch int edge effects, but are otherwise unnecessarily computed. Delay the computation until we know that switch sources are indeed required and avoid the computation otherwise. --- compiler/rustc_middle/src/mir/mod.rs | 2 ++ compiler/rustc_mir_dataflow/src/framework/direction.rs | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 682f3734d309e..4d26840fd624d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -580,6 +580,8 @@ impl<'tcx> Body<'tcx> { self.predecessor_cache.compute(&self.basic_blocks) } + /// `body.switch_sources()[target][switch]` returns a list of switch values + /// that lead to a `target` block from a `switch` block. #[inline] pub fn switch_sources(&self) -> &SwitchSources { self.switch_source_cache.compute(&self.basic_blocks) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 93118dfeb7737..327002219db6b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -269,9 +269,9 @@ impl Direction for Backward { mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => { let mut applier = BackwardSwitchIntEdgeEffectsApplier { + body, pred, exit_state, - values: &body.switch_sources()[bb][pred], bb, propagate: &mut propagate, effects_applied: false, @@ -305,9 +305,9 @@ impl Direction for Backward { } struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> { + body: &'a mir::Body<'a>, pred: BasicBlock, exit_state: &'a mut D, - values: &'a [Option], bb: BasicBlock, propagate: &'a mut F, @@ -322,7 +322,8 @@ where fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { assert!(!self.effects_applied); - let targets = self.values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); + let values = &self.body.switch_sources()[self.bb][self.pred]; + let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); let mut tmp = None; for target in targets { From 2be012a0c664bf1ee90af0e5cac9a3e3e24f4666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 8 May 2022 00:00:00 +0000 Subject: [PATCH 2/2] Use sparse representation of switch sources to avoid quadratic space overhead --- compiler/rustc_middle/src/mir/mod.rs | 4 ++-- compiler/rustc_middle/src/mir/switch_sources.rs | 12 +++++------- .../rustc_mir_dataflow/src/framework/direction.rs | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4d26840fd624d..2c97c7704e77d 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -580,8 +580,8 @@ impl<'tcx> Body<'tcx> { self.predecessor_cache.compute(&self.basic_blocks) } - /// `body.switch_sources()[target][switch]` returns a list of switch values - /// that lead to a `target` block from a `switch` block. + /// `body.switch_sources()[&(target, switch)]` returns a list of switch + /// values that lead to a `target` block from a `switch` block. #[inline] pub fn switch_sources(&self) -> &SwitchSources { self.switch_source_cache.compute(&self.basic_blocks) diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs index 7f62b4d0dbab9..adeeec70d1c0b 100644 --- a/compiler/rustc_middle/src/mir/switch_sources.rs +++ b/compiler/rustc_middle/src/mir/switch_sources.rs @@ -2,6 +2,7 @@ //! `Predecessors`/`PredecessorCache`. use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_map::FxHashMap; use rustc_data_structures::sync::OnceCell; use rustc_index::vec::IndexVec; use rustc_serialize as serialize; @@ -9,7 +10,7 @@ use smallvec::SmallVec; use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind}; -pub type SwitchSources = IndexVec; 1]>>>; +pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option; 1]>>; #[derive(Clone, Debug)] pub(super) struct SwitchSourceCache { @@ -35,19 +36,16 @@ impl SwitchSourceCache { basic_blocks: &IndexVec>, ) -> &SwitchSources { self.cache.get_or_init(|| { - let mut switch_sources = IndexVec::from_elem( - IndexVec::from_elem(SmallVec::new(), basic_blocks), - basic_blocks, - ); + let mut switch_sources: SwitchSources = FxHashMap::default(); for (bb, data) in basic_blocks.iter_enumerated() { if let Some(Terminator { kind: TerminatorKind::SwitchInt { targets, .. }, .. }) = &data.terminator { for (value, target) in targets.iter() { - switch_sources[target][bb].push(Some(value)); + switch_sources.entry((target, bb)).or_default().push(Some(value)); } - switch_sources[targets.otherwise()][bb].push(None); + switch_sources.entry((targets.otherwise(), bb)).or_default().push(None); } } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 327002219db6b..18795128b8571 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -322,7 +322,7 @@ where fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { assert!(!self.effects_applied); - let values = &self.body.switch_sources()[self.bb][self.pred]; + let values = &self.body.switch_sources()[&(self.bb, self.pred)]; let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); let mut tmp = None;