Skip to content

Commit 005de38

Browse files
authored
Rollup merge of #136959 - nnethercote:simplify-SwitchSources, r=tmiasko
Simplify switch sources `SwitchSources` and the code around it can be simplified. r? `@tmiasko`
2 parents 2162e9d + 3b81d9d commit 005de38

File tree

6 files changed

+68
-46
lines changed

6 files changed

+68
-46
lines changed

compiler/rustc_middle/src/mir/basic_blocks.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,22 @@ pub struct BasicBlocks<'tcx> {
2020
// Typically 95%+ of basic blocks have 4 or fewer predecessors.
2121
type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
2222

23-
type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
23+
/// Each `(target, switch)` entry in the map contains a list of switch values
24+
/// that lead to a `target` block from a `switch` block.
25+
///
26+
/// Note: this type is currently never instantiated, because it's only used for
27+
/// `BasicBlocks::switch_sources`, which is only called by backwards analyses
28+
/// that do `SwitchInt` handling, and we don't have any of those, not even in
29+
/// tests. See #95120 and #94576.
30+
type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[SwitchTargetValue; 1]>>;
31+
32+
#[derive(Debug, Clone, Copy)]
33+
pub enum SwitchTargetValue {
34+
// A normal switch value.
35+
Normal(u128),
36+
// The final "otherwise" fallback value.
37+
Otherwise,
38+
}
2439

2540
#[derive(Clone, Default, Debug)]
2641
struct Cache {
@@ -70,8 +85,8 @@ impl<'tcx> BasicBlocks<'tcx> {
7085
})
7186
}
7287

73-
/// `switch_sources()[&(target, switch)]` returns a list of switch
74-
/// values that lead to a `target` block from a `switch` block.
88+
/// Returns info about switch values that lead from one block to another
89+
/// block. See `SwitchSources`.
7590
#[inline]
7691
pub fn switch_sources(&self) -> &SwitchSources {
7792
self.cache.switch_sources.get_or_init(|| {
@@ -82,9 +97,15 @@ impl<'tcx> BasicBlocks<'tcx> {
8297
}) = &data.terminator
8398
{
8499
for (value, target) in targets.iter() {
85-
switch_sources.entry((target, bb)).or_default().push(Some(value));
100+
switch_sources
101+
.entry((target, bb))
102+
.or_default()
103+
.push(SwitchTargetValue::Normal(value));
86104
}
87-
switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
105+
switch_sources
106+
.entry((targets.otherwise(), bb))
107+
.or_default()
108+
.push(SwitchTargetValue::Otherwise);
88109
}
89110
}
90111
switch_sources

compiler/rustc_middle/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::fmt::{self, Debug, Formatter};
77
use std::ops::{Index, IndexMut};
88
use std::{iter, mem};
99

10-
pub use basic_blocks::BasicBlocks;
10+
pub use basic_blocks::{BasicBlocks, SwitchTargetValue};
1111
use either::Either;
1212
use polonius_engine::Atom;
1313
use rustc_abi::{FieldIdx, VariantIdx};

compiler/rustc_middle/src/mir/syntax.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -1015,22 +1015,30 @@ impl TerminatorKind<'_> {
10151015

10161016
#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
10171017
pub struct SwitchTargets {
1018-
/// Possible values. The locations to branch to in each case
1019-
/// are found in the corresponding indices from the `targets` vector.
1018+
/// Possible values. For each value, the location to branch to is found in
1019+
/// the corresponding element in the `targets` vector.
10201020
pub(super) values: SmallVec<[Pu128; 1]>,
10211021

1022-
/// Possible branch sites. The last element of this vector is used
1023-
/// for the otherwise branch, so targets.len() == values.len() + 1
1024-
/// should hold.
1022+
/// Possible branch targets. The last element of this vector is used for
1023+
/// the "otherwise" branch, so `targets.len() == values.len() + 1` always
1024+
/// holds.
10251025
//
1026-
// This invariant is quite non-obvious and also could be improved.
1027-
// One way to make this invariant is to have something like this instead:
1026+
// Note: This invariant is non-obvious and easy to violate. This would be a
1027+
// more rigorous representation:
10281028
//
1029-
// branches: Vec<(ConstInt, BasicBlock)>,
1030-
// otherwise: Option<BasicBlock> // exhaustive if None
1029+
// normal: SmallVec<[(Pu128, BasicBlock); 1]>,
1030+
// otherwise: BasicBlock,
10311031
//
1032-
// However we’ve decided to keep this as-is until we figure a case
1033-
// where some other approach seems to be strictly better than other.
1032+
// But it's important to have the targets in a sliceable type, because
1033+
// target slices show up elsewhere. E.g. `TerminatorKind::InlineAsm` has a
1034+
// boxed slice, and `TerminatorKind::FalseEdge` has a single target that
1035+
// can be converted to a slice with `slice::from_ref`.
1036+
//
1037+
// Why does this matter? In functions like `TerminatorKind::successors` we
1038+
// return `impl Iterator` and a non-slice-of-targets representation here
1039+
// causes problems because multiple different concrete iterator types would
1040+
// be involved and we would need a boxed trait object, which requires an
1041+
// allocation, which is expensive if done frequently.
10341042
pub(super) targets: SmallVec<[BasicBlock; 2]>,
10351043
}
10361044

compiler/rustc_mir_dataflow/src/framework/direction.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use std::ops::RangeInclusive;
22

3-
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
3+
use rustc_middle::mir::{
4+
self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
5+
};
46

57
use super::visitor::ResultsVisitor;
6-
use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
8+
use super::{Analysis, Effect, EffectIndex, Results};
79

810
pub trait Direction {
911
const IS_FORWARD: bool;
@@ -112,14 +114,10 @@ impl Direction for Backward {
112114

113115
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
114116
if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
115-
let values = &body.basic_blocks.switch_sources()[&(block, pred)];
116-
let targets =
117-
values.iter().map(|&value| SwitchIntTarget { value, target: block });
118-
119117
let mut tmp = analysis.bottom_value(body);
120-
for target in targets {
121-
tmp.clone_from(&exit_state);
122-
analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, target);
118+
for &value in &body.basic_blocks.switch_sources()[&(block, pred)] {
119+
tmp.clone_from(exit_state);
120+
analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value);
123121
propagate(pred, &tmp);
124122
}
125123
} else {
@@ -292,12 +290,9 @@ impl Direction for Forward {
292290
if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
293291
let mut tmp = analysis.bottom_value(body);
294292
for (value, target) in targets.iter() {
295-
tmp.clone_from(&exit_state);
296-
analysis.apply_switch_int_edge_effect(
297-
&mut data,
298-
&mut tmp,
299-
SwitchIntTarget { value: Some(value), target },
300-
);
293+
tmp.clone_from(exit_state);
294+
let value = SwitchTargetValue::Normal(value);
295+
analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value);
301296
propagate(target, &tmp);
302297
}
303298

@@ -308,7 +303,7 @@ impl Direction for Forward {
308303
analysis.apply_switch_int_edge_effect(
309304
&mut data,
310305
exit_state,
311-
SwitchIntTarget { value: None, target: otherwise },
306+
SwitchTargetValue::Otherwise,
312307
);
313308
propagate(otherwise, exit_state);
314309
} else {

compiler/rustc_mir_dataflow/src/framework/mod.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ use rustc_data_structures::work_queue::WorkQueue;
3838
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
3939
use rustc_index::{Idx, IndexVec};
4040
use rustc_middle::bug;
41-
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
41+
use rustc_middle::mir::{
42+
self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges, traversal,
43+
};
4244
use rustc_middle::ty::TyCtxt;
4345
use tracing::error;
4446

@@ -220,7 +222,7 @@ pub trait Analysis<'tcx> {
220222
&mut self,
221223
_data: &mut Self::SwitchIntData,
222224
_state: &mut Self::Domain,
223-
_edge: SwitchIntTarget,
225+
_value: SwitchTargetValue,
224226
) {
225227
unreachable!();
226228
}
@@ -430,10 +432,5 @@ impl EffectIndex {
430432
}
431433
}
432434

433-
pub struct SwitchIntTarget {
434-
pub value: Option<u128>,
435-
pub target: BasicBlock,
436-
}
437-
438435
#[cfg(test)]
439436
mod tests;

compiler/rustc_mir_dataflow/src/impls/initialized.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use rustc_abi::VariantIdx;
44
use rustc_index::Idx;
55
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
66
use rustc_middle::bug;
7-
use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges};
7+
use rustc_middle::mir::{
8+
self, Body, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
9+
};
810
use rustc_middle::ty::util::Discr;
911
use rustc_middle::ty::{self, TyCtxt};
1012
use tracing::{debug, instrument};
1113

1214
use crate::drop_flag_effects::DropFlagState;
13-
use crate::framework::SwitchIntTarget;
1415
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
1516
use crate::{
1617
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
@@ -422,9 +423,9 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
422423
&mut self,
423424
data: &mut Self::SwitchIntData,
424425
state: &mut Self::Domain,
425-
edge: SwitchIntTarget,
426+
value: SwitchTargetValue,
426427
) {
427-
if let Some(value) = edge.value {
428+
if let SwitchTargetValue::Normal(value) = value {
428429
// Kill all move paths that correspond to variants we know to be inactive along this
429430
// particular outgoing edge of a `SwitchInt`.
430431
drop_flag_effects::on_all_inactive_variants(
@@ -535,9 +536,9 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
535536
&mut self,
536537
data: &mut Self::SwitchIntData,
537538
state: &mut Self::Domain,
538-
edge: SwitchIntTarget,
539+
value: SwitchTargetValue,
539540
) {
540-
if let Some(value) = edge.value {
541+
if let SwitchTargetValue::Normal(value) = value {
541542
// Mark all move paths that correspond to variants other than this one as maybe
542543
// uninitialized (in reality, they are *definitely* uninitialized).
543544
drop_flag_effects::on_all_inactive_variants(

0 commit comments

Comments
 (0)