Address review comments
* Add lazily computed `switch_sources` data structure * Don't assume a target has only one associated value
This commit is contained in:
parent
ee7413b94c
commit
37ebd47ddb
3 changed files with 106 additions and 7 deletions
|
@ -45,6 +45,7 @@ use std::{iter, mem, option};
|
|||
use self::graph_cyclic_cache::GraphIsCyclicCache;
|
||||
use self::predecessors::{PredecessorCache, Predecessors};
|
||||
pub use self::query::*;
|
||||
use self::switch_sources::{SwitchSourceCache, SwitchSources};
|
||||
|
||||
pub mod coverage;
|
||||
mod generic_graph;
|
||||
|
@ -58,6 +59,7 @@ mod predecessors;
|
|||
pub mod pretty;
|
||||
mod query;
|
||||
pub mod spanview;
|
||||
mod switch_sources;
|
||||
pub mod tcx;
|
||||
pub mod terminator;
|
||||
pub use terminator::*;
|
||||
|
@ -284,6 +286,7 @@ pub struct Body<'tcx> {
|
|||
pub is_polymorphic: bool,
|
||||
|
||||
predecessor_cache: PredecessorCache,
|
||||
switch_source_cache: SwitchSourceCache,
|
||||
is_cyclic: GraphIsCyclicCache,
|
||||
|
||||
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
|
@ -332,6 +335,7 @@ impl<'tcx> Body<'tcx> {
|
|||
required_consts: Vec::new(),
|
||||
is_polymorphic: false,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
switch_source_cache: SwitchSourceCache::new(),
|
||||
is_cyclic: GraphIsCyclicCache::new(),
|
||||
tainted_by_errors,
|
||||
};
|
||||
|
@ -360,6 +364,7 @@ impl<'tcx> Body<'tcx> {
|
|||
var_debug_info: Vec::new(),
|
||||
is_polymorphic: false,
|
||||
predecessor_cache: PredecessorCache::new(),
|
||||
switch_source_cache: SwitchSourceCache::new(),
|
||||
is_cyclic: GraphIsCyclicCache::new(),
|
||||
tainted_by_errors: None,
|
||||
};
|
||||
|
@ -380,6 +385,7 @@ impl<'tcx> Body<'tcx> {
|
|||
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
|
||||
// invalidate the caches.
|
||||
self.predecessor_cache.invalidate();
|
||||
self.switch_source_cache.invalidate();
|
||||
self.is_cyclic.invalidate();
|
||||
&mut self.basic_blocks
|
||||
}
|
||||
|
@ -389,6 +395,7 @@ impl<'tcx> Body<'tcx> {
|
|||
&mut self,
|
||||
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
|
||||
self.predecessor_cache.invalidate();
|
||||
self.switch_source_cache.invalidate();
|
||||
self.is_cyclic.invalidate();
|
||||
(&mut self.basic_blocks, &mut self.local_decls)
|
||||
}
|
||||
|
@ -402,6 +409,7 @@ impl<'tcx> Body<'tcx> {
|
|||
&mut Vec<VarDebugInfo<'tcx>>,
|
||||
) {
|
||||
self.predecessor_cache.invalidate();
|
||||
self.switch_source_cache.invalidate();
|
||||
self.is_cyclic.invalidate();
|
||||
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
|
||||
}
|
||||
|
@ -529,6 +537,11 @@ impl<'tcx> Body<'tcx> {
|
|||
self.predecessor_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn switch_sources(&self) -> &SwitchSources {
|
||||
self.switch_source_cache.compute(&self.basic_blocks)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dominators(&self) -> Dominators<BasicBlock> {
|
||||
dominators(self)
|
||||
|
|
82
compiler/rustc_middle/src/mir/switch_sources.rs
Normal file
82
compiler/rustc_middle/src/mir/switch_sources.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
|
||||
//! `Predecessors`/`PredecessorCache`.
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::OnceCell;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_serialize as serialize;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
|
||||
|
||||
pub type SwitchSources = IndexVec<BasicBlock, IndexVec<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 = IndexVec::from_elem(
|
||||
IndexVec::from_elem(SmallVec::new(), basic_blocks),
|
||||
basic_blocks,
|
||||
);
|
||||
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[targets.otherwise()][bb].push(None);
|
||||
}
|
||||
}
|
||||
|
||||
switch_sources
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: serialize::Encoder> serialize::Encodable<S> for SwitchSourceCache {
|
||||
#[inline]
|
||||
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_unit()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: serialize::Decoder> serialize::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
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeFoldableAndLiftImpls! {
|
||||
SwitchSourceCache,
|
||||
}
|
|
@ -267,11 +267,11 @@ impl Direction for Backward {
|
|||
propagate(pred, &tmp);
|
||||
}
|
||||
|
||||
mir::TerminatorKind::SwitchInt { ref targets, ref discr, switch_ty: _ } => {
|
||||
mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => {
|
||||
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
|
||||
pred,
|
||||
exit_state,
|
||||
targets,
|
||||
values: &body.switch_sources()[bb][pred],
|
||||
bb,
|
||||
propagate: &mut propagate,
|
||||
effects_applied: false,
|
||||
|
@ -309,7 +309,7 @@ impl Direction for Backward {
|
|||
struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> {
|
||||
pred: BasicBlock,
|
||||
exit_state: &'a mut D,
|
||||
targets: &'a SwitchTargets,
|
||||
values: &'a [Option<u128>],
|
||||
bb: BasicBlock,
|
||||
propagate: &'a mut F,
|
||||
|
||||
|
@ -324,10 +324,14 @@ where
|
|||
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
|
||||
assert!(!self.effects_applied);
|
||||
|
||||
let value =
|
||||
self.targets.iter().find_map(|(value, target)| (target == self.bb).then_some(value));
|
||||
apply_edge_effect(self.exit_state, SwitchIntTarget { value, target: self.bb });
|
||||
(self.propagate)(self.pred, self.exit_state);
|
||||
let targets = self.values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
|
||||
|
||||
let mut tmp = None;
|
||||
for target in targets {
|
||||
let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
|
||||
apply_edge_effect(tmp, target);
|
||||
(self.propagate)(self.pred, tmp);
|
||||
}
|
||||
|
||||
self.effects_applied = true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue