Use sparse representation of switch sources

to avoid quadratic space overhead
This commit is contained in:
Tomasz Miąsko 2022-05-08 00:00:00 +00:00
parent fbc3cc18be
commit 2be012a0c6
3 changed files with 8 additions and 10 deletions

View File

@ -580,8 +580,8 @@ impl<'tcx> Body<'tcx> {
self.predecessor_cache.compute(&self.basic_blocks) self.predecessor_cache.compute(&self.basic_blocks)
} }
/// `body.switch_sources()[target][switch]` returns a list of switch values /// `body.switch_sources()[&(target, switch)]` returns a list of switch
/// that lead to a `target` block from a `switch` block. /// values that lead to a `target` block from a `switch` block.
#[inline] #[inline]
pub fn switch_sources(&self) -> &SwitchSources { pub fn switch_sources(&self) -> &SwitchSources {
self.switch_source_cache.compute(&self.basic_blocks) self.switch_source_cache.compute(&self.basic_blocks)

View File

@ -2,6 +2,7 @@
//! `Predecessors`/`PredecessorCache`. //! `Predecessors`/`PredecessorCache`.
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::sync::OnceCell; use rustc_data_structures::sync::OnceCell;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_serialize as serialize; use rustc_serialize as serialize;
@ -9,7 +10,7 @@ use smallvec::SmallVec;
use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind}; use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
pub type SwitchSources = IndexVec<BasicBlock, IndexVec<BasicBlock, SmallVec<[Option<u128>; 1]>>>; pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(super) struct SwitchSourceCache { pub(super) struct SwitchSourceCache {
@ -35,19 +36,16 @@ impl SwitchSourceCache {
basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>, basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
) -> &SwitchSources { ) -> &SwitchSources {
self.cache.get_or_init(|| { self.cache.get_or_init(|| {
let mut switch_sources = IndexVec::from_elem( let mut switch_sources: SwitchSources = FxHashMap::default();
IndexVec::from_elem(SmallVec::new(), basic_blocks),
basic_blocks,
);
for (bb, data) in basic_blocks.iter_enumerated() { for (bb, data) in basic_blocks.iter_enumerated() {
if let Some(Terminator { if let Some(Terminator {
kind: TerminatorKind::SwitchInt { targets, .. }, .. kind: TerminatorKind::SwitchInt { targets, .. }, ..
}) = &data.terminator }) = &data.terminator
{ {
for (value, target) in targets.iter() { 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);
} }
} }

View File

@ -322,7 +322,7 @@ where
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
assert!(!self.effects_applied); 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 targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
let mut tmp = None; let mut tmp = None;