Allocate candidate vectors as we sort them

This commit is contained in:
Nadrieril 2024-03-02 02:14:13 +01:00
parent 3d3b321c60
commit 8c3688cbb5
7 changed files with 56 additions and 88 deletions

View File

@ -1653,10 +1653,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&'b mut [&'c mut Candidate<'pat, 'tcx>], &'b mut [&'c mut Candidate<'pat, 'tcx>],
FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'pat, 'tcx>>>, FxIndexMap<TestBranch<'tcx>, Vec<&'b mut Candidate<'pat, 'tcx>>>,
) { ) {
// For each of the N possible outcomes, create a (initially empty) vector of candidates. // For each of the possible outcomes, collect vector of candidates that apply if the test
// Those are the candidates that apply if the test has that particular outcome. // has that particular outcome.
let mut target_candidates: FxIndexMap<_, Vec<&mut Candidate<'pat, 'tcx>>> = let mut target_candidates: FxIndexMap<_, Vec<&mut Candidate<'_, '_>>> = Default::default();
test.targets().into_iter().map(|branch| (branch, Vec::new())).collect();
let total_candidate_count = candidates.len(); let total_candidate_count = candidates.len();
@ -1668,7 +1667,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
break; break;
}; };
let (candidate, rest) = candidates.split_first_mut().unwrap(); let (candidate, rest) = candidates.split_first_mut().unwrap();
target_candidates[&branch].push(candidate); target_candidates.entry(branch).or_insert_with(Vec::new).push(candidate);
candidates = rest; candidates = rest;
} }
@ -1809,31 +1808,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block otherwise_block
}; };
// For each outcome of test, process the candidates that still // For each outcome of test, process the candidates that still apply.
// apply. Collect a list of blocks where control flow will
// branch if one of the `target_candidate` sets is not
// exhaustive.
let target_blocks: FxIndexMap<_, _> = target_candidates let target_blocks: FxIndexMap<_, _> = target_candidates
.into_iter() .into_iter()
.map(|(branch, mut candidates)| { .map(|(branch, mut candidates)| {
if !candidates.is_empty() { let candidate_start = self.cfg.start_new_block();
let candidate_start = self.cfg.start_new_block(); self.match_candidates(
self.match_candidates( span,
span, scrutinee_span,
scrutinee_span, candidate_start,
candidate_start, remainder_start,
remainder_start, &mut *candidates,
&mut *candidates, );
); (branch, candidate_start)
(branch, candidate_start)
} else {
(branch, remainder_start)
}
}) })
.collect(); .collect();
// Perform the test, branching to one of N blocks. // Perform the test, branching to one of N blocks.
self.perform_test(span, scrutinee_span, start_block, &match_place, &test, target_blocks); self.perform_test(
span,
scrutinee_span,
start_block,
remainder_start,
&match_place,
&test,
target_blocks,
);
} }
/// Determine the fake borrows that are needed from a set of places that /// Determine the fake borrows that are needed from a set of places that

View File

@ -127,6 +127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match_start_span: Span, match_start_span: Span,
scrutinee_span: Span, scrutinee_span: Span,
block: BasicBlock, block: BasicBlock,
otherwise_block: BasicBlock,
place_builder: &PlaceBuilder<'tcx>, place_builder: &PlaceBuilder<'tcx>,
test: &Test<'tcx>, test: &Test<'tcx>,
target_blocks: FxIndexMap<TestBranch<'tcx>, BasicBlock>, target_blocks: FxIndexMap<TestBranch<'tcx>, BasicBlock>,
@ -134,14 +135,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place = place_builder.to_place(self); let place = place_builder.to_place(self);
let place_ty = place.ty(&self.local_decls, self.tcx); let place_ty = place.ty(&self.local_decls, self.tcx);
debug!(?place, ?place_ty); debug!(?place, ?place_ty);
let target_block = |branch| target_blocks[&branch]; let target_block = |branch| target_blocks.get(&branch).copied().unwrap_or(otherwise_block);
let source_info = self.source_info(test.span); let source_info = self.source_info(test.span);
match test.kind { match test.kind {
TestKind::Switch { adt_def, ref variants } => { TestKind::Switch { adt_def, ref variants } => {
// Variants is a BitVec of indexes into adt_def.variants. // Variants is a BitVec of indexes into adt_def.variants.
let num_enum_variants = adt_def.variants().len(); let num_enum_variants = adt_def.variants().len();
debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
let otherwise_block = target_block(TestBranch::Failure); let otherwise_block = target_block(TestBranch::Failure);
let tcx = self.tcx; let tcx = self.tcx;
let switch_targets = SwitchTargets::new( let switch_targets = SwitchTargets::new(
@ -185,7 +185,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestKind::SwitchInt { ref options } => { TestKind::SwitchInt { ref options } => {
// The switch may be inexhaustive so we have a catch-all block // The switch may be inexhaustive so we have a catch-all block
debug_assert_eq!(options.len() + 1, target_blocks.len());
let otherwise_block = target_block(TestBranch::Failure); let otherwise_block = target_block(TestBranch::Failure);
let switch_targets = SwitchTargets::new( let switch_targets = SwitchTargets::new(
options options
@ -201,7 +200,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
TestKind::If => { TestKind::If => {
debug_assert_eq!(target_blocks.len(), 2);
let success_block = target_block(TestBranch::Success); let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure); let fail_block = target_block(TestBranch::Failure);
let terminator = let terminator =
@ -211,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestKind::Eq { value, ty } => { TestKind::Eq { value, ty } => {
let tcx = self.tcx; let tcx = self.tcx;
debug_assert_eq!(target_blocks.len(), 2);
let success_block = target_block(TestBranch::Success); let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure); let fail_block = target_block(TestBranch::Failure);
if let ty::Adt(def, _) = ty.kind() if let ty::Adt(def, _) = ty.kind()
@ -290,7 +287,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
TestKind::Range(ref range) => { TestKind::Range(ref range) => {
debug_assert_eq!(target_blocks.len(), 2);
let success = target_block(TestBranch::Success); let success = target_block(TestBranch::Success);
let fail = target_block(TestBranch::Failure); let fail = target_block(TestBranch::Failure);
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
@ -337,7 +333,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// expected = <N> // expected = <N>
let expected = self.push_usize(block, source_info, len); let expected = self.push_usize(block, source_info, len);
debug_assert_eq!(target_blocks.len(), 2);
let success_block = target_block(TestBranch::Success); let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure); let fail_block = target_block(TestBranch::Failure);
// result = actual == expected OR result = actual < expected // result = actual == expected OR result = actual < expected
@ -753,33 +748,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
impl<'tcx> Test<'tcx> {
pub(super) fn targets(&self) -> Vec<TestBranch<'tcx>> {
match self.kind {
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } | TestKind::If => {
vec![TestBranch::Success, TestBranch::Failure]
}
TestKind::Switch { adt_def, .. } => {
// While the switch that we generate doesn't test for all
// variants, we have a target for each variant and the
// otherwise case, and we make sure that all of the cases not
// specified have the same block.
adt_def
.variants()
.indices()
.map(|idx| TestBranch::Variant(idx))
.chain([TestBranch::Failure])
.collect()
}
TestKind::SwitchInt { ref options } => options
.iter()
.map(|(val, bits)| TestBranch::Constant(*val, *bits))
.chain([TestBranch::Failure])
.collect(),
}
}
}
fn is_switch_ty(ty: Ty<'_>) -> bool { fn is_switch_ty(ty: Ty<'_>) -> bool {
ty.is_integral() || ty.is_char() ty.is_integral() || ty.is_char()
} }

View File

@ -25,7 +25,7 @@ fn main() -> () {
StorageLive(_3); StorageLive(_3);
_3 = const true; _3 = const true;
PlaceMention(_3); PlaceMention(_3);
switchInt(_3) -> [0: bb6, otherwise: bb4]; switchInt(_3) -> [0: bb4, otherwise: bb6];
} }
bb3: { bb3: {
@ -34,8 +34,7 @@ fn main() -> () {
} }
bb4: { bb4: {
_0 = const (); falseEdge -> [real: bb8, imaginary: bb6];
goto -> bb13;
} }
bb5: { bb5: {
@ -43,7 +42,8 @@ fn main() -> () {
} }
bb6: { bb6: {
falseEdge -> [real: bb8, imaginary: bb4]; _0 = const ();
goto -> bb13;
} }
bb7: { bb7: {

View File

@ -28,7 +28,7 @@ fn full_tested_match() -> () {
_2 = Option::<i32>::Some(const 42_i32); _2 = Option::<i32>::Some(const 42_i32);
PlaceMention(_2); PlaceMention(_2);
_3 = discriminant(_2); _3 = discriminant(_2);
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1]; switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
@ -37,20 +37,20 @@ fn full_tested_match() -> () {
} }
bb2: { bb2: {
_1 = (const 3_i32, const 3_i32); falseEdge -> [real: bb7, imaginary: bb3];
goto -> bb13;
} }
bb3: { bb3: {
goto -> bb1; falseEdge -> [real: bb12, imaginary: bb5];
} }
bb4: { bb4: {
falseEdge -> [real: bb7, imaginary: bb5]; goto -> bb1;
} }
bb5: { bb5: {
falseEdge -> [real: bb12, imaginary: bb2]; _1 = (const 3_i32, const 3_i32);
goto -> bb13;
} }
bb6: { bb6: {
@ -91,7 +91,7 @@ fn full_tested_match() -> () {
bb11: { bb11: {
StorageDead(_7); StorageDead(_7);
StorageDead(_6); StorageDead(_6);
goto -> bb5; goto -> bb3;
} }
bb12: { bb12: {

View File

@ -28,7 +28,7 @@ fn full_tested_match2() -> () {
_2 = Option::<i32>::Some(const 42_i32); _2 = Option::<i32>::Some(const 42_i32);
PlaceMention(_2); PlaceMention(_2);
_3 = discriminant(_2); _3 = discriminant(_2);
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1]; switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
@ -37,18 +37,10 @@ fn full_tested_match2() -> () {
} }
bb2: { bb2: {
falseEdge -> [real: bb12, imaginary: bb5]; falseEdge -> [real: bb7, imaginary: bb5];
} }
bb3: { bb3: {
goto -> bb1;
}
bb4: {
falseEdge -> [real: bb7, imaginary: bb2];
}
bb5: {
StorageLive(_9); StorageLive(_9);
_9 = ((_2 as Some).0: i32); _9 = ((_2 as Some).0: i32);
StorageLive(_10); StorageLive(_10);
@ -59,6 +51,14 @@ fn full_tested_match2() -> () {
goto -> bb13; goto -> bb13;
} }
bb4: {
goto -> bb1;
}
bb5: {
falseEdge -> [real: bb12, imaginary: bb3];
}
bb6: { bb6: {
goto -> bb1; goto -> bb1;
} }
@ -97,7 +97,7 @@ fn full_tested_match2() -> () {
bb11: { bb11: {
StorageDead(_7); StorageDead(_7);
StorageDead(_6); StorageDead(_6);
falseEdge -> [real: bb5, imaginary: bb2]; falseEdge -> [real: bb3, imaginary: bb5];
} }
bb12: { bb12: {

View File

@ -30,7 +30,7 @@
StorageDead(_5); StorageDead(_5);
StorageDead(_4); StorageDead(_4);
_8 = discriminant((_3.0: std::option::Option<u32>)); _8 = discriminant((_3.0: std::option::Option<u32>));
- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; - switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
+ StorageLive(_11); + StorageLive(_11);
+ _11 = discriminant((_3.1: std::option::Option<u32>)); + _11 = discriminant((_3.1: std::option::Option<u32>));
+ StorageLive(_12); + StorageLive(_12);
@ -48,12 +48,12 @@
bb2: { bb2: {
- _6 = discriminant((_3.1: std::option::Option<u32>)); - _6 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _6) -> [0: bb5, otherwise: bb1]; - switchInt(move _6) -> [1: bb4, otherwise: bb1];
- } - }
- -
- bb3: { - bb3: {
- _7 = discriminant((_3.1: std::option::Option<u32>)); - _7 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _7) -> [1: bb4, otherwise: bb1]; - switchInt(move _7) -> [0: bb5, otherwise: bb1];
- } - }
- -
- bb4: { - bb4: {

View File

@ -36,7 +36,7 @@
StorageDead(_5); StorageDead(_5);
StorageDead(_4); StorageDead(_4);
_8 = discriminant((_3.0: std::option::Option<u32>)); _8 = discriminant((_3.0: std::option::Option<u32>));
switchInt(move _8) -> [0: bb2, 1: bb4, otherwise: bb1]; switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
} }
bb1: { bb1: {
@ -45,17 +45,17 @@
bb2: { bb2: {
_6 = discriminant((_3.1: std::option::Option<u32>)); _6 = discriminant((_3.1: std::option::Option<u32>));
switchInt(move _6) -> [0: bb3, 1: bb7, otherwise: bb1]; switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1];
} }
bb3: { bb3: {
_0 = const 3_u32; _7 = discriminant((_3.1: std::option::Option<u32>));
goto -> bb8; switchInt(move _7) -> [0: bb4, 1: bb7, otherwise: bb1];
} }
bb4: { bb4: {
_7 = discriminant((_3.1: std::option::Option<u32>)); _0 = const 3_u32;
switchInt(move _7) -> [0: bb6, 1: bb5, otherwise: bb1]; goto -> bb8;
} }
bb5: { bb5: {