Skip to content

Commit 02f733b

Browse files
authored
Rollup merge of #156169 - nnethercote:simplify-SwitchInt-stuff, r=cjgillot
Change `SwitchInt` handling in dataflow analysis. We call `get_switch_int_data` once for the switch and then pass that data to `apply_switch_int_edge_effect` for each switch target. The only case in practice is `MaybePlacesSwitchIntData` which does an awkward thing, maintaining an index into the discriminants and updating it on each call to `apply_switch_int_edge_effect`. This commit changes things to do more work up front in `get_switch_int_data`, in order to then do less work in `apply_switch_int_edge_effect`. This avoids the need for the `variants` and `next_discr` methods and the discriminants index. Overall it's a little simpler. r? @cjgillot
2 parents 0711aa9 + d0eab57 commit 02f733b

6 files changed

Lines changed: 80 additions & 80 deletions

File tree

compiler/rustc_middle/src/mir/basic_blocks.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ pub struct BasicBlocks<'tcx> {
2121
// Typically 95%+ of basic blocks have 4 or fewer predecessors.
2222
type Predecessors = IndexVec<BasicBlock, SmallVec<[BasicBlock; 4]>>;
2323

24-
#[derive(Debug, Clone, Copy)]
25-
pub enum SwitchTargetValue {
26-
// A normal switch value.
27-
Normal(u128),
28-
// The final "otherwise" fallback value.
29-
Otherwise,
30-
}
31-
3224
#[derive(Clone, Default, Debug)]
3325
struct Cache {
3426
predecessors: OnceLock<Predecessors>,

compiler/rustc_middle/src/mir/mod.rs

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

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

compiler/rustc_mir_dataflow/src/framework/direction.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use std::ops::RangeInclusive;
22

33
use rustc_middle::bug;
4-
use rustc_middle::mir::{
5-
self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
6-
};
4+
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
75

86
use super::visitor::ResultsVisitor;
9-
use super::{Analysis, Effect, EffectIndex};
7+
use super::{Analysis, Effect, EffectIndex, SwitchTargetIndex};
108

119
pub trait Direction {
1210
const IS_FORWARD: bool;
@@ -113,8 +111,8 @@ impl Direction for Backward {
113111
propagate(pred, &tmp);
114112
}
115113

116-
mir::TerminatorKind::SwitchInt { ref discr, .. } => {
117-
if let Some(_data) = analysis.get_switch_int_data(pred, discr) {
114+
mir::TerminatorKind::SwitchInt { ref targets, ref discr } => {
115+
if let Some(_data) = analysis.get_switch_int_data(pred, targets, discr) {
118116
bug!(
119117
"SwitchInt edge effects are unsupported in backward dataflow analyses"
120118
);
@@ -283,23 +281,22 @@ impl Direction for Forward {
283281
}
284282
}
285283
TerminatorEdges::SwitchInt { targets, discr } => {
286-
if let Some(mut data) = analysis.get_switch_int_data(block, discr) {
284+
if let Some(mut data) = analysis.get_switch_int_data(block, targets, discr) {
287285
let mut tmp = analysis.bottom_value(body);
288-
for (value, target) in targets.iter() {
286+
for (i, (_value, target)) in targets.iter().enumerate() {
289287
tmp.clone_from(exit_state);
290-
let value = SwitchTargetValue::Normal(value);
291-
analysis.apply_switch_int_edge_effect(&mut data, &mut tmp, value, targets);
288+
let target_idx = SwitchTargetIndex::Normal(i);
289+
analysis.apply_switch_int_edge_effect(&mut tmp, &mut data, target_idx);
292290
propagate(target, &tmp);
293291
}
294292

295293
// Once we get to the final, "otherwise" branch, there is no need to preserve
296294
// `exit_state`, so pass it directly to `apply_switch_int_edge_effect` to save
297295
// a clone of the dataflow state.
298296
analysis.apply_switch_int_edge_effect(
299-
&mut data,
300297
exit_state,
301-
SwitchTargetValue::Otherwise,
302-
targets,
298+
&mut data,
299+
SwitchTargetIndex::Otherwise,
303300
);
304301
propagate(targets.otherwise(), exit_state);
305302
} else {

compiler/rustc_mir_dataflow/src/framework/mod.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ 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::{
42-
self, BasicBlock, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges, traversal,
43-
};
41+
use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
4442
use rustc_middle::ty::TyCtxt;
4543
use tracing::error;
4644

@@ -212,6 +210,7 @@ pub trait Analysis<'tcx> {
212210
fn get_switch_int_data(
213211
&self,
214212
_block: mir::BasicBlock,
213+
_targets: &mir::SwitchTargets,
215214
_discr: &mir::Operand<'tcx>,
216215
) -> Option<Self::SwitchIntData> {
217216
None
@@ -220,10 +219,9 @@ pub trait Analysis<'tcx> {
220219
/// See comments on `get_switch_int_data`.
221220
fn apply_switch_int_edge_effect(
222221
&self,
223-
_data: &mut Self::SwitchIntData,
224222
_state: &mut Self::Domain,
225-
_value: SwitchTargetValue,
226-
_targets: &mir::SwitchTargets,
223+
_data: &mut Self::SwitchIntData,
224+
_target_idx: SwitchTargetIndex,
227225
) {
228226
unreachable!();
229227
}
@@ -313,6 +311,14 @@ pub trait Analysis<'tcx> {
313311
}
314312
}
315313

314+
#[derive(Debug, Clone, Copy)]
315+
pub enum SwitchTargetIndex {
316+
// Index of a normal switch target.
317+
Normal(usize),
318+
// The final "otherwise" fallback target.
319+
Otherwise,
320+
}
321+
316322
/// The legal operations for a transfer function in a gen/kill problem.
317323
pub trait GenKill<T> {
318324
/// Inserts `elem` into the state vector.

compiler/rustc_mir_dataflow/src/impls/initialized.rs

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,38 @@ 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::{
8-
self, Body, CallReturnPlaces, Location, SwitchTargetValue, TerminatorEdges,
9-
};
10-
use rustc_middle::ty::util::Discr;
7+
use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges};
118
use rustc_middle::ty::{self, TyCtxt};
129
use smallvec::SmallVec;
1310
use tracing::{debug, instrument};
1411

1512
use crate::drop_flag_effects::{DropFlagState, InactiveVariants};
1613
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
1714
use crate::{
18-
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
19-
drop_flag_effects_for_location, on_all_children_bits, on_lookup_result_bits,
15+
Analysis, GenKill, MaybeReachable, SwitchTargetIndex, drop_flag_effects,
16+
drop_flag_effects_for_function_entry, drop_flag_effects_for_location, on_all_children_bits,
17+
on_lookup_result_bits,
2018
};
2119

2220
// Used by both `MaybeInitializedPlaces` and `MaybeUninitializedPlaces`.
2321
pub struct MaybePlacesSwitchIntData<'tcx> {
2422
enum_place: mir::Place<'tcx>,
25-
discriminants: Vec<(VariantIdx, Discr<'tcx>)>,
26-
index: usize,
27-
}
2823

29-
impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
30-
/// Creates a `SmallVec` mapping each target in `targets` to its `VariantIdx`.
31-
fn variants(&mut self, targets: &mir::SwitchTargets) -> SmallVec<[VariantIdx; 4]> {
32-
self.index = 0;
33-
targets.all_values().iter().map(|value| self.next_discr(value.get())).collect()
34-
}
35-
36-
// The discriminant order in the `SwitchInt` targets should match the order yielded by
37-
// `AdtDef::discriminants`. We rely on this to match each discriminant in the targets to its
38-
// corresponding variant in linear time.
39-
fn next_discr(&mut self, value: u128) -> VariantIdx {
40-
// An out-of-bounds abort will occur if the discriminant ordering isn't as described above.
41-
loop {
42-
let (variant, discr) = self.discriminants[self.index];
43-
self.index += 1;
44-
if discr.val == value {
45-
return variant;
46-
}
47-
}
48-
}
24+
// Variant indices targeted by the SwitchInt. For example, if you have:
25+
// ```
26+
// enum E { A = 1, B = 3, C = 5, D = 7 }
27+
// ```
28+
// and a `SwitchInt(A -> bb1, C -> bb2, _ -> bb3)`, this vec will contain `[0, 2]` because
29+
// those are the variant indices for `A` and `C`.
30+
variants: SmallVec<[VariantIdx; 4]>,
4931
}
5032

5133
impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
5234
fn new(
5335
tcx: TyCtxt<'tcx>,
5436
body: &Body<'tcx>,
5537
block: mir::BasicBlock,
38+
targets: &mir::SwitchTargets,
5639
discr: &mir::Operand<'tcx>,
5740
) -> Option<Self> {
5841
let Some(discr) = discr.place() else { return None };
@@ -76,11 +59,29 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> {
7659
{
7760
match enum_place.ty(body, tcx).ty.kind() {
7861
ty::Adt(enum_def, _) => {
79-
return Some(MaybePlacesSwitchIntData {
80-
enum_place,
81-
discriminants: enum_def.discriminants(tcx).collect(),
82-
index: 0,
83-
});
62+
// The value of each discriminant, in AdtDef order.
63+
let discriminant_vals: SmallVec<[u128; 4]> =
64+
enum_def.discriminants(tcx).map(|(_, discr)| discr.val).collect();
65+
let mut i = 0;
66+
67+
// For each value in the SwitchInt, find the VariantIdx for the variant
68+
// with that value. This works because `discriminant_vals` and
69+
// `targets.all_values()` are guaranteed to list variants in the same
70+
// order. (If that ever changes we will get out-of-bounds panics here.)
71+
let variants = targets
72+
.all_values()
73+
.iter()
74+
.map(|value| {
75+
loop {
76+
if discriminant_vals[i] == value.get() {
77+
return VariantIdx::new(i);
78+
}
79+
i += 1;
80+
}
81+
})
82+
.collect();
83+
84+
return Some(MaybePlacesSwitchIntData { enum_place, variants });
8485
}
8586

8687
// `Rvalue::Discriminant` is also used to get the active yield point for a
@@ -452,26 +453,28 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
452453
fn get_switch_int_data(
453454
&self,
454455
block: mir::BasicBlock,
456+
targets: &mir::SwitchTargets,
455457
discr: &mir::Operand<'tcx>,
456458
) -> Option<Self::SwitchIntData> {
457459
if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration {
458460
return None;
459461
}
460462

461-
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
463+
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, targets, discr)
462464
}
463465

464466
fn apply_switch_int_edge_effect(
465467
&self,
466-
data: &mut Self::SwitchIntData,
467468
state: &mut Self::Domain,
468-
value: SwitchTargetValue,
469-
targets: &mir::SwitchTargets,
469+
data: &mut Self::SwitchIntData,
470+
target_idx: SwitchTargetIndex,
470471
) {
471-
let inactive_variants = match value {
472-
SwitchTargetValue::Normal(value) => InactiveVariants::Active(data.next_discr(value)),
473-
SwitchTargetValue::Otherwise if self.exclude_inactive_in_otherwise => {
474-
InactiveVariants::Inactives(data.variants(targets))
472+
let inactive_variants = match target_idx {
473+
SwitchTargetIndex::Normal(target_idx) => {
474+
InactiveVariants::Active(data.variants[target_idx])
475+
}
476+
SwitchTargetIndex::Otherwise if self.exclude_inactive_in_otherwise => {
477+
InactiveVariants::Inactives(data.variants.clone())
475478
}
476479
_ => return,
477480
};
@@ -568,6 +571,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
568571
fn get_switch_int_data(
569572
&self,
570573
block: mir::BasicBlock,
574+
targets: &mir::SwitchTargets,
571575
discr: &mir::Operand<'tcx>,
572576
) -> Option<Self::SwitchIntData> {
573577
if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration {
@@ -578,20 +582,21 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
578582
return None;
579583
}
580584

581-
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, discr)
585+
MaybePlacesSwitchIntData::new(self.tcx, self.body, block, targets, discr)
582586
}
583587

584588
fn apply_switch_int_edge_effect(
585589
&self,
586-
data: &mut Self::SwitchIntData,
587590
state: &mut Self::Domain,
588-
value: SwitchTargetValue,
589-
targets: &mir::SwitchTargets,
591+
data: &mut Self::SwitchIntData,
592+
target_idx: SwitchTargetIndex,
590593
) {
591-
let inactive_variants = match value {
592-
SwitchTargetValue::Normal(value) => InactiveVariants::Active(data.next_discr(value)),
593-
SwitchTargetValue::Otherwise if self.include_inactive_in_otherwise => {
594-
InactiveVariants::Inactives(data.variants(targets))
594+
let inactive_variants = match target_idx {
595+
SwitchTargetIndex::Normal(target_idx) => {
596+
InactiveVariants::Active(data.variants[target_idx])
597+
}
598+
SwitchTargetIndex::Otherwise if self.include_inactive_in_otherwise => {
599+
InactiveVariants::Inactives(data.variants.clone())
595600
}
596601
_ => return,
597602
};

compiler/rustc_mir_dataflow/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub use self::drop_flag_effects::{
1717
};
1818
pub use self::framework::{
1919
Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
20-
Results, ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results,
21-
visit_results,
20+
Results, ResultsCursor, ResultsVisitor, SwitchTargetIndex, fmt, graphviz, lattice,
21+
visit_reachable_results, visit_results,
2222
};
2323
use self::move_paths::MoveData;
2424

0 commit comments

Comments
 (0)