Skip to content

Commit 37ebd47

Browse files
committed
Address review comments
* Add lazily computed `switch_sources` data structure * Don't assume a target has only one associated value
1 parent ee7413b commit 37ebd47

File tree

3 files changed

+106
-7
lines changed

3 files changed

+106
-7
lines changed

compiler/rustc_middle/src/mir/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use std::{iter, mem, option};
4545
use self::graph_cyclic_cache::GraphIsCyclicCache;
4646
use self::predecessors::{PredecessorCache, Predecessors};
4747
pub use self::query::*;
48+
use self::switch_sources::{SwitchSourceCache, SwitchSources};
4849

4950
pub mod coverage;
5051
mod generic_graph;
@@ -58,6 +59,7 @@ mod predecessors;
5859
pub mod pretty;
5960
mod query;
6061
pub mod spanview;
62+
mod switch_sources;
6163
pub mod tcx;
6264
pub mod terminator;
6365
pub use terminator::*;
@@ -284,6 +286,7 @@ pub struct Body<'tcx> {
284286
pub is_polymorphic: bool,
285287

286288
predecessor_cache: PredecessorCache,
289+
switch_source_cache: SwitchSourceCache,
287290
is_cyclic: GraphIsCyclicCache,
288291

289292
pub tainted_by_errors: Option<ErrorGuaranteed>,
@@ -332,6 +335,7 @@ impl<'tcx> Body<'tcx> {
332335
required_consts: Vec::new(),
333336
is_polymorphic: false,
334337
predecessor_cache: PredecessorCache::new(),
338+
switch_source_cache: SwitchSourceCache::new(),
335339
is_cyclic: GraphIsCyclicCache::new(),
336340
tainted_by_errors,
337341
};
@@ -360,6 +364,7 @@ impl<'tcx> Body<'tcx> {
360364
var_debug_info: Vec::new(),
361365
is_polymorphic: false,
362366
predecessor_cache: PredecessorCache::new(),
367+
switch_source_cache: SwitchSourceCache::new(),
363368
is_cyclic: GraphIsCyclicCache::new(),
364369
tainted_by_errors: None,
365370
};
@@ -380,6 +385,7 @@ impl<'tcx> Body<'tcx> {
380385
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
381386
// invalidate the caches.
382387
self.predecessor_cache.invalidate();
388+
self.switch_source_cache.invalidate();
383389
self.is_cyclic.invalidate();
384390
&mut self.basic_blocks
385391
}
@@ -389,6 +395,7 @@ impl<'tcx> Body<'tcx> {
389395
&mut self,
390396
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
391397
self.predecessor_cache.invalidate();
398+
self.switch_source_cache.invalidate();
392399
self.is_cyclic.invalidate();
393400
(&mut self.basic_blocks, &mut self.local_decls)
394401
}
@@ -402,6 +409,7 @@ impl<'tcx> Body<'tcx> {
402409
&mut Vec<VarDebugInfo<'tcx>>,
403410
) {
404411
self.predecessor_cache.invalidate();
412+
self.switch_source_cache.invalidate();
405413
self.is_cyclic.invalidate();
406414
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
407415
}
@@ -529,6 +537,11 @@ impl<'tcx> Body<'tcx> {
529537
self.predecessor_cache.compute(&self.basic_blocks)
530538
}
531539

540+
#[inline]
541+
pub fn switch_sources(&self) -> &SwitchSources {
542+
self.switch_source_cache.compute(&self.basic_blocks)
543+
}
544+
532545
#[inline]
533546
pub fn dominators(&self) -> Dominators<BasicBlock> {
534547
dominators(self)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//! Lazily compute the inverse of each `SwitchInt`'s switch targets. Modeled after
2+
//! `Predecessors`/`PredecessorCache`.
3+
4+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5+
use rustc_data_structures::sync::OnceCell;
6+
use rustc_index::vec::IndexVec;
7+
use rustc_serialize as serialize;
8+
use smallvec::SmallVec;
9+
10+
use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
11+
12+
pub type SwitchSources = IndexVec<BasicBlock, IndexVec<BasicBlock, SmallVec<[Option<u128>; 1]>>>;
13+
14+
#[derive(Clone, Debug)]
15+
pub(super) struct SwitchSourceCache {
16+
cache: OnceCell<SwitchSources>,
17+
}
18+
19+
impl SwitchSourceCache {
20+
#[inline]
21+
pub(super) fn new() -> Self {
22+
SwitchSourceCache { cache: OnceCell::new() }
23+
}
24+
25+
/// Invalidates the switch source cache.
26+
#[inline]
27+
pub(super) fn invalidate(&mut self) {
28+
self.cache = OnceCell::new();
29+
}
30+
31+
/// Returns the switch sources for this MIR.
32+
#[inline]
33+
pub(super) fn compute(
34+
&self,
35+
basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
36+
) -> &SwitchSources {
37+
self.cache.get_or_init(|| {
38+
let mut switch_sources = IndexVec::from_elem(
39+
IndexVec::from_elem(SmallVec::new(), basic_blocks),
40+
basic_blocks,
41+
);
42+
for (bb, data) in basic_blocks.iter_enumerated() {
43+
if let Some(Terminator {
44+
kind: TerminatorKind::SwitchInt { targets, .. }, ..
45+
}) = &data.terminator
46+
{
47+
for (value, target) in targets.iter() {
48+
switch_sources[target][bb].push(Some(value));
49+
}
50+
switch_sources[targets.otherwise()][bb].push(None);
51+
}
52+
}
53+
54+
switch_sources
55+
})
56+
}
57+
}
58+
59+
impl<S: serialize::Encoder> serialize::Encodable<S> for SwitchSourceCache {
60+
#[inline]
61+
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
62+
s.emit_unit()
63+
}
64+
}
65+
66+
impl<D: serialize::Decoder> serialize::Decodable<D> for SwitchSourceCache {
67+
#[inline]
68+
fn decode(_: &mut D) -> Self {
69+
Self::new()
70+
}
71+
}
72+
73+
impl<CTX> HashStable<CTX> for SwitchSourceCache {
74+
#[inline]
75+
fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
76+
// do nothing
77+
}
78+
}
79+
80+
TrivialTypeFoldableAndLiftImpls! {
81+
SwitchSourceCache,
82+
}

compiler/rustc_mir_dataflow/src/framework/direction.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,11 @@ impl Direction for Backward {
267267
propagate(pred, &tmp);
268268
}
269269

270-
mir::TerminatorKind::SwitchInt { ref targets, ref discr, switch_ty: _ } => {
270+
mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => {
271271
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
272272
pred,
273273
exit_state,
274-
targets,
274+
values: &body.switch_sources()[bb][pred],
275275
bb,
276276
propagate: &mut propagate,
277277
effects_applied: false,
@@ -309,7 +309,7 @@ impl Direction for Backward {
309309
struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> {
310310
pred: BasicBlock,
311311
exit_state: &'a mut D,
312-
targets: &'a SwitchTargets,
312+
values: &'a [Option<u128>],
313313
bb: BasicBlock,
314314
propagate: &'a mut F,
315315

@@ -324,10 +324,14 @@ where
324324
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
325325
assert!(!self.effects_applied);
326326

327-
let value =
328-
self.targets.iter().find_map(|(value, target)| (target == self.bb).then_some(value));
329-
apply_edge_effect(self.exit_state, SwitchIntTarget { value, target: self.bb });
330-
(self.propagate)(self.pred, self.exit_state);
327+
let targets = self.values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
328+
329+
let mut tmp = None;
330+
for target in targets {
331+
let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
332+
apply_edge_effect(tmp, target);
333+
(self.propagate)(self.pred, tmp);
334+
}
331335

332336
self.effects_applied = true;
333337
}

0 commit comments

Comments
 (0)