summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/mir/switch_sources.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/mir/switch_sources.rs')
-rw-r--r--compiler/rustc_middle/src/mir/switch_sources.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs
new file mode 100644
index 000000000..b91c0c257
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/switch_sources.rs
@@ -0,0 +1,78 @@
+//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
+//! `Predecessors`/`PredecessorCache`.
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_index::vec::IndexVec;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use smallvec::SmallVec;
+
+use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
+
+pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
+
+#[derive(Clone, Debug)]
+pub(super) struct SwitchSourceCache {
+ cache: OnceCell<SwitchSources>,
+}
+
+impl SwitchSourceCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ SwitchSourceCache { cache: OnceCell::new() }
+ }
+
+ /// Invalidates the switch source cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ self.cache = OnceCell::new();
+ }
+
+ /// Returns the switch sources for this MIR.
+ #[inline]
+ pub(super) fn compute(
+ &self,
+ basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
+ ) -> &SwitchSources {
+ self.cache.get_or_init(|| {
+ 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.entry((target, bb)).or_default().push(Some(value));
+ }
+ switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
+ }
+ }
+
+ switch_sources
+ })
+ }
+}
+
+impl<S: Encoder> Encodable<S> for SwitchSourceCache {
+ #[inline]
+ fn encode(&self, _s: &mut S) {}
+}
+
+impl<D: Decoder> Decodable<D> for SwitchSourceCache {
+ #[inline]
+ fn decode(_: &mut D) -> Self {
+ Self::new()
+ }
+}
+
+impl<CTX> HashStable<CTX> for SwitchSourceCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeTraversalAndLiftImpls! {
+ SwitchSourceCache,
+}