Skip to content

Commit 3e030b3

Browse files
committed
Return the otherwise_block instead of passing it as argument
This saves a few blocks and matches the common `unpack!` paradigm.
1 parent fc40247 commit 3e030b3

19 files changed

+333
-461
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+29-57
Original file line numberDiff line numberDiff line change
@@ -1313,11 +1313,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13131313
candidates: &mut [&mut Candidate<'pat, 'tcx>],
13141314
refutable: bool,
13151315
) -> BasicBlock {
1316+
// This will generate code to test scrutinee_place and branch to the appropriate arm block.
13161317
// See the doc comment on `match_candidates` for why we have an otherwise block.
1317-
let otherwise_block = self.cfg.start_new_block();
1318-
1319-
// This will generate code to test scrutinee_place and branch to the appropriate arm block
1320-
self.match_candidates(match_start_span, scrutinee_span, block, otherwise_block, candidates);
1318+
let otherwise_block =
1319+
self.match_candidates(match_start_span, scrutinee_span, block, candidates);
13211320

13221321
// Link each leaf candidate to the `false_edge_start_block` of the next one.
13231322
let mut previous_candidate: Option<&mut Candidate<'_, '_>> = None;
@@ -1368,27 +1367,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
13681367
otherwise_block
13691368
}
13701369

1371-
/// The main match algorithm. It begins with a set of candidates
1372-
/// `candidates` and has the job of generating code to determine
1373-
/// which of these candidates, if any, is the correct one. The
1370+
/// The main match algorithm. It begins with a set of candidates `candidates` and has the job of
1371+
/// generating code that branches to an appropriate block if the scrutinee matches one of these
1372+
/// candidates. The
13741373
/// candidates are sorted such that the first item in the list
13751374
/// has the highest priority. When a candidate is found to match
13761375
/// the value, we will set and generate a branch to the appropriate
13771376
/// pre-binding block.
13781377
///
1379-
/// If we find that *NONE* of the candidates apply, we branch to `otherwise_block`.
1378+
/// If none of the candidates apply, we continue to the returned `otherwise_block`.
13801379
///
13811380
/// It might be surprising that the input can be non-exhaustive.
1382-
/// Indeed, initially, it is not, because all matches are
1381+
/// Indeed, for matches, initially, it is not, because all matches are
13831382
/// exhaustive in Rust. But during processing we sometimes divide
13841383
/// up the list of candidates and recurse with a non-exhaustive
13851384
/// list. This is how our lowering approach (called "backtracking
13861385
/// automaton" in the literature) works.
13871386
/// See [`Builder::test_candidates`] for more details.
13881387
///
1389-
/// If `fake_borrows` is `Some`, then places which need fake borrows
1390-
/// will be added to it.
1391-
///
13921388
/// For an example of how we use `otherwise_block`, consider:
13931389
/// ```
13941390
/// # fn foo((x, y): (bool, bool)) -> u32 {
@@ -1413,7 +1409,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14131409
/// }
14141410
/// if y {
14151411
/// if x {
1416-
/// // This is actually unreachable because the `(true, true)` case was handled above.
1412+
/// // This is actually unreachable because the `(true, true)` case was handled above,
1413+
/// // but we don't know that from within the lowering algorithm.
14171414
/// // continue
14181415
/// } else {
14191416
/// return 3
@@ -1430,25 +1427,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14301427
/// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`].
14311428
///
14321429
/// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller
1433-
/// code size at the expense of non-optimal code paths.
1430+
/// code size so we accept non-optimal code paths.
14341431
#[instrument(skip(self), level = "debug")]
14351432
fn match_candidates(
14361433
&mut self,
14371434
span: Span,
14381435
scrutinee_span: Span,
14391436
start_block: BasicBlock,
1440-
otherwise_block: BasicBlock,
14411437
candidates: &mut [&mut Candidate<'_, 'tcx>],
1442-
) {
1438+
) -> BasicBlock {
14431439
ensure_sufficient_stack(|| {
1444-
self.match_candidates_with_enough_stack(
1445-
span,
1446-
scrutinee_span,
1447-
start_block,
1448-
otherwise_block,
1449-
candidates,
1450-
)
1451-
});
1440+
self.match_candidates_with_enough_stack(span, scrutinee_span, start_block, candidates)
1441+
})
14521442
}
14531443

14541444
/// Construct the decision tree for `candidates`. Don't call this, call `match_candidates`
@@ -1458,9 +1448,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14581448
span: Span,
14591449
scrutinee_span: Span,
14601450
start_block: BasicBlock,
1461-
otherwise_block: BasicBlock,
14621451
candidates: &mut [&mut Candidate<'_, 'tcx>],
1463-
) {
1452+
) -> BasicBlock {
14641453
if let [first, ..] = candidates {
14651454
if first.false_edge_start_block.is_none() {
14661455
first.false_edge_start_block = Some(start_block);
@@ -1471,9 +1460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14711460
let rest = match candidates {
14721461
[] => {
14731462
// If there are no candidates that still need testing, we're done.
1474-
let source_info = self.source_info(span);
1475-
self.cfg.goto(start_block, source_info, otherwise_block);
1476-
return;
1463+
return start_block;
14771464
}
14781465
[first, remaining @ ..] if first.match_pairs.is_empty() => {
14791466
// The first candidate has satisfied all its match pairs; we link it up and continue
@@ -1494,13 +1481,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14941481

14951482
// Process any candidates that remain.
14961483
let BlockAnd(start_block, remaining_candidates) = rest;
1497-
self.match_candidates(
1498-
span,
1499-
scrutinee_span,
1500-
start_block,
1501-
otherwise_block,
1502-
remaining_candidates,
1503-
);
1484+
self.match_candidates(span, scrutinee_span, start_block, remaining_candidates)
15041485
}
15051486

15061487
/// Link up matched candidates.
@@ -1605,14 +1586,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16051586
}
16061587

16071588
// Process the expanded candidates.
1608-
let remainder_start = self.cfg.start_new_block();
1609-
// There might be new or-patterns obtained from expanding the old ones, so we call
1610-
// `match_candidates` again.
1611-
self.match_candidates(
1589+
let remainder_start = self.match_candidates(
16121590
span,
16131591
scrutinee_span,
16141592
start_block,
1615-
remainder_start,
16161593
expanded_candidates.as_mut_slice(),
16171594
);
16181595

@@ -1711,6 +1688,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17111688
self.merge_trivial_subcandidates(candidate);
17121689

17131690
if !candidate.match_pairs.is_empty() {
1691+
let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span);
1692+
let source_info = self.source_info(or_span);
17141693
// If more match pairs remain, test them after each subcandidate.
17151694
// We could add them to the or-candidates before the call to `test_or_pattern` but this
17161695
// would make it impossible to detect simplifiable or-patterns. That would guarantee
@@ -1724,6 +1703,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17241703
assert!(leaf_candidate.match_pairs.is_empty());
17251704
leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned());
17261705
let or_start = leaf_candidate.pre_binding_block.unwrap();
1706+
let otherwise =
1707+
self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]);
17271708
// In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q,
17281709
// R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching
17291710
// directly to `last_otherwise`. If there is a guard,
@@ -1734,13 +1715,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17341715
} else {
17351716
last_otherwise.unwrap()
17361717
};
1737-
self.match_candidates(
1738-
span,
1739-
scrutinee_span,
1740-
or_start,
1741-
or_otherwise,
1742-
&mut [leaf_candidate],
1743-
);
1718+
self.cfg.goto(otherwise, source_info, or_otherwise);
17441719
});
17451720
}
17461721
}
@@ -2019,15 +1994,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20191994
let target_blocks: FxIndexMap<_, _> = target_candidates
20201995
.into_iter()
20211996
.map(|(branch, mut candidates)| {
2022-
let candidate_start = self.cfg.start_new_block();
2023-
self.match_candidates(
2024-
span,
2025-
scrutinee_span,
2026-
candidate_start,
2027-
remainder_start,
2028-
&mut *candidates,
2029-
);
2030-
(branch, candidate_start)
1997+
let branch_start = self.cfg.start_new_block();
1998+
let branch_otherwise =
1999+
self.match_candidates(span, scrutinee_span, branch_start, &mut *candidates);
2000+
let source_info = self.source_info(span);
2001+
self.cfg.goto(branch_otherwise, source_info, remainder_start);
2002+
(branch, branch_start)
20312003
})
20322004
.collect();
20332005

tests/mir-opt/building/issue_101867.main.built.after.mir

+7-11
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ fn main() -> () {
2727
StorageLive(_5);
2828
PlaceMention(_1);
2929
_6 = discriminant(_1);
30-
switchInt(move _6) -> [1: bb5, otherwise: bb4];
30+
switchInt(move _6) -> [1: bb4, otherwise: bb3];
3131
}
3232

3333
bb1: {
3434
StorageLive(_3);
3535
StorageLive(_4);
36-
_4 = begin_panic::<&str>(const "explicit panic") -> bb9;
36+
_4 = begin_panic::<&str>(const "explicit panic") -> bb8;
3737
}
3838

3939
bb2: {
@@ -43,35 +43,31 @@ fn main() -> () {
4343
}
4444

4545
bb3: {
46-
goto -> bb8;
46+
goto -> bb7;
4747
}
4848

4949
bb4: {
50-
goto -> bb3;
50+
falseEdge -> [real: bb6, imaginary: bb3];
5151
}
5252

5353
bb5: {
54-
falseEdge -> [real: bb7, imaginary: bb3];
54+
goto -> bb3;
5555
}
5656

5757
bb6: {
58-
goto -> bb4;
59-
}
60-
61-
bb7: {
6258
_5 = ((_1 as Some).0: u8);
6359
_0 = const ();
6460
StorageDead(_5);
6561
StorageDead(_1);
6662
return;
6763
}
6864

69-
bb8: {
65+
bb7: {
7066
StorageDead(_5);
7167
goto -> bb1;
7268
}
7369

74-
bb9 (cleanup): {
70+
bb8 (cleanup): {
7571
resume;
7672
}
7773
}

tests/mir-opt/building/issue_49232.main.built.after.mir

+15-19
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ fn main() -> () {
1717
}
1818

1919
bb1: {
20-
falseUnwind -> [real: bb2, unwind: bb15];
20+
falseUnwind -> [real: bb2, unwind: bb14];
2121
}
2222

2323
bb2: {
2424
StorageLive(_2);
2525
StorageLive(_3);
2626
_3 = const true;
2727
PlaceMention(_3);
28-
switchInt(_3) -> [0: bb5, otherwise: bb7];
28+
switchInt(_3) -> [0: bb4, otherwise: bb6];
2929
}
3030

3131
bb3: {
@@ -34,63 +34,59 @@ fn main() -> () {
3434
}
3535

3636
bb4: {
37-
goto -> bb3;
37+
falseEdge -> [real: bb8, imaginary: bb6];
3838
}
3939

4040
bb5: {
41-
falseEdge -> [real: bb9, imaginary: bb7];
41+
goto -> bb3;
4242
}
4343

4444
bb6: {
45-
goto -> bb4;
45+
_0 = const ();
46+
goto -> bb13;
4647
}
4748

4849
bb7: {
49-
_0 = const ();
50-
goto -> bb14;
50+
goto -> bb3;
5151
}
5252

5353
bb8: {
54-
goto -> bb4;
54+
_2 = const 4_i32;
55+
goto -> bb11;
5556
}
5657

5758
bb9: {
58-
_2 = const 4_i32;
59-
goto -> bb12;
59+
unreachable;
6060
}
6161

6262
bb10: {
63-
unreachable;
63+
goto -> bb11;
6464
}
6565

6666
bb11: {
67-
goto -> bb12;
68-
}
69-
70-
bb12: {
7167
FakeRead(ForLet(None), _2);
7268
StorageDead(_3);
7369
StorageLive(_5);
7470
StorageLive(_6);
7571
_6 = &_2;
76-
_5 = std::mem::drop::<&i32>(move _6) -> [return: bb13, unwind: bb15];
72+
_5 = std::mem::drop::<&i32>(move _6) -> [return: bb12, unwind: bb14];
7773
}
7874

79-
bb13: {
75+
bb12: {
8076
StorageDead(_6);
8177
StorageDead(_5);
8278
_1 = const ();
8379
StorageDead(_2);
8480
goto -> bb1;
8581
}
8682

87-
bb14: {
83+
bb13: {
8884
StorageDead(_3);
8985
StorageDead(_2);
9086
return;
9187
}
9288

93-
bb15 (cleanup): {
89+
bb14 (cleanup): {
9490
resume;
9591
}
9692
}

0 commit comments

Comments
 (0)