Skip to content

Commit f704f3b

Browse files
committed
Auto merge of rust-lang#119112 - Nadrieril:remove-target_blocks-hack, r=matthewjasper
match lowering: Remove the `make_target_blocks` hack This hack was introduced 4 years ago in [`a1d0266` (rust-lang#60730)](rust-lang@a1d0266) to improve LLVM optimization time, specifically noticed in the `encoding` benchmark. Measurements today indicate it is no longer needed. r? `@matthewjasper`
2 parents 57ad505 + 31bad13 commit f704f3b

File tree

4 files changed

+86
-92
lines changed

4 files changed

+86
-92
lines changed

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

+43-51
Original file line numberDiff line numberDiff line change
@@ -1699,59 +1699,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16991699
debug!("tested_candidates: {}", total_candidate_count - candidates.len());
17001700
debug!("untested_candidates: {}", candidates.len());
17011701

1702-
// HACK(matthewjasper) This is a closure so that we can let the test
1703-
// create its blocks before the rest of the match. This currently
1704-
// improves the speed of llvm when optimizing long string literal
1705-
// matches
1706-
let make_target_blocks = move |this: &mut Self| -> Vec<BasicBlock> {
1707-
// The block that we should branch to if none of the
1708-
// `target_candidates` match. This is either the block where we
1709-
// start matching the untested candidates if there are any,
1710-
// otherwise it's the `otherwise_block`.
1711-
let remainder_start = &mut None;
1712-
let remainder_start =
1713-
if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
1714-
1715-
// For each outcome of test, process the candidates that still
1716-
// apply. Collect a list of blocks where control flow will
1717-
// branch if one of the `target_candidate` sets is not
1718-
// exhaustive.
1719-
let target_blocks: Vec<_> = target_candidates
1720-
.into_iter()
1721-
.map(|mut candidates| {
1722-
if !candidates.is_empty() {
1723-
let candidate_start = this.cfg.start_new_block();
1724-
this.match_candidates(
1725-
span,
1726-
scrutinee_span,
1727-
candidate_start,
1728-
remainder_start,
1729-
&mut *candidates,
1730-
fake_borrows,
1731-
);
1732-
candidate_start
1733-
} else {
1734-
*remainder_start.get_or_insert_with(|| this.cfg.start_new_block())
1735-
}
1736-
})
1737-
.collect();
1738-
1739-
if !candidates.is_empty() {
1740-
let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
1741-
this.match_candidates(
1742-
span,
1743-
scrutinee_span,
1744-
remainder_start,
1745-
otherwise_block,
1746-
candidates,
1747-
fake_borrows,
1748-
);
1749-
};
1702+
// The block that we should branch to if none of the
1703+
// `target_candidates` match. This is either the block where we
1704+
// start matching the untested candidates if there are any,
1705+
// otherwise it's the `otherwise_block`.
1706+
let remainder_start = &mut None;
1707+
let remainder_start =
1708+
if candidates.is_empty() { &mut *otherwise_block } else { remainder_start };
1709+
1710+
// For each outcome of test, process the candidates that still
1711+
// apply. Collect a list of blocks where control flow will
1712+
// branch if one of the `target_candidate` sets is not
1713+
// exhaustive.
1714+
let target_blocks: Vec<_> = target_candidates
1715+
.into_iter()
1716+
.map(|mut candidates| {
1717+
if !candidates.is_empty() {
1718+
let candidate_start = self.cfg.start_new_block();
1719+
self.match_candidates(
1720+
span,
1721+
scrutinee_span,
1722+
candidate_start,
1723+
remainder_start,
1724+
&mut *candidates,
1725+
fake_borrows,
1726+
);
1727+
candidate_start
1728+
} else {
1729+
*remainder_start.get_or_insert_with(|| self.cfg.start_new_block())
1730+
}
1731+
})
1732+
.collect();
17501733

1751-
target_blocks
1752-
};
1734+
if !candidates.is_empty() {
1735+
let remainder_start = remainder_start.unwrap_or_else(|| self.cfg.start_new_block());
1736+
self.match_candidates(
1737+
span,
1738+
scrutinee_span,
1739+
remainder_start,
1740+
otherwise_block,
1741+
candidates,
1742+
fake_borrows,
1743+
);
1744+
}
17531745

1754-
self.perform_test(span, scrutinee_span, block, &match_place, &test, make_target_blocks);
1746+
self.perform_test(span, scrutinee_span, block, &match_place, &test, target_blocks);
17551747
}
17561748

17571749
/// Determine the fake borrows that are needed from a set of places that

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

+22-20
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
147147
}
148148
}
149149

150-
#[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
150+
#[instrument(skip(self, target_blocks, place_builder), level = "debug")]
151151
pub(super) fn perform_test(
152152
&mut self,
153153
match_start_span: Span,
154154
scrutinee_span: Span,
155155
block: BasicBlock,
156156
place_builder: &PlaceBuilder<'tcx>,
157157
test: &Test<'tcx>,
158-
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
158+
target_blocks: Vec<BasicBlock>,
159159
) {
160160
let place = place_builder.to_place(self);
161161
let place_ty = place.ty(&self.local_decls, self.tcx);
@@ -164,7 +164,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
164164
let source_info = self.source_info(test.span);
165165
match test.kind {
166166
TestKind::Switch { adt_def, ref variants } => {
167-
let target_blocks = make_target_blocks(self);
168167
// Variants is a BitVec of indexes into adt_def.variants.
169168
let num_enum_variants = adt_def.variants().len();
170169
debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
@@ -210,7 +209,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
210209
}
211210

212211
TestKind::SwitchInt { switch_ty, ref options } => {
213-
let target_blocks = make_target_blocks(self);
214212
let terminator = if *switch_ty.kind() == ty::Bool {
215213
assert!(!options.is_empty() && options.len() <= 2);
216214
let [first_bb, second_bb] = *target_blocks else {
@@ -240,6 +238,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
240238

241239
TestKind::Eq { value, ty } => {
242240
let tcx = self.tcx;
241+
let [success_block, fail_block] = *target_blocks else {
242+
bug!("`TestKind::Eq` should have two target blocks")
243+
};
243244
if let ty::Adt(def, _) = ty.kind()
244245
&& Some(def.did()) == tcx.lang_items().string()
245246
{
@@ -280,38 +281,43 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
280281
);
281282
self.non_scalar_compare(
282283
eq_block,
283-
make_target_blocks,
284+
success_block,
285+
fail_block,
284286
source_info,
285287
value,
286288
ref_str,
287289
ref_str_ty,
288290
);
289-
return;
290-
}
291-
if !ty.is_scalar() {
291+
} else if !ty.is_scalar() {
292292
// Use `PartialEq::eq` instead of `BinOp::Eq`
293293
// (the binop can only handle primitives)
294294
self.non_scalar_compare(
295295
block,
296-
make_target_blocks,
296+
success_block,
297+
fail_block,
297298
source_info,
298299
value,
299300
place,
300301
ty,
301302
);
302-
} else if let [success, fail] = *make_target_blocks(self) {
303+
} else {
303304
assert_eq!(value.ty(), ty);
304305
let expect = self.literal_operand(test.span, value);
305306
let val = Operand::Copy(place);
306-
self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
307-
} else {
308-
bug!("`TestKind::Eq` should have two target blocks");
307+
self.compare(
308+
block,
309+
success_block,
310+
fail_block,
311+
source_info,
312+
BinOp::Eq,
313+
expect,
314+
val,
315+
);
309316
}
310317
}
311318

312319
TestKind::Range(ref range) => {
313320
let lower_bound_success = self.cfg.start_new_block();
314-
let target_blocks = make_target_blocks(self);
315321

316322
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
317323
// FIXME: skip useless comparison when the range is half-open.
@@ -341,8 +347,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
341347
}
342348

343349
TestKind::Len { len, op } => {
344-
let target_blocks = make_target_blocks(self);
345-
346350
let usize_ty = self.tcx.types.usize;
347351
let actual = self.temp(usize_ty, test.span);
348352

@@ -406,7 +410,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
406410
fn non_scalar_compare(
407411
&mut self,
408412
block: BasicBlock,
409-
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
413+
success_block: BasicBlock,
414+
fail_block: BasicBlock,
410415
source_info: SourceInfo,
411416
value: Const<'tcx>,
412417
mut val: Place<'tcx>,
@@ -531,9 +536,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
531536
);
532537
self.diverge_from(block);
533538

534-
let [success_block, fail_block] = *make_target_blocks(self) else {
535-
bug!("`TestKind::Eq` should have two target blocks")
536-
};
537539
// check the result
538540
self.cfg.terminate(
539541
eq_block,

tests/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir

+7-7
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,22 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
3838

3939
bb4: {
4040
_5 = Le(const 6_u32, (_1.3: u32));
41-
switchInt(move _5) -> [0: bb6, otherwise: bb5];
41+
switchInt(move _5) -> [0: bb5, otherwise: bb7];
4242
}
4343

4444
bb5: {
45-
_6 = Le((_1.3: u32), const 9_u32);
46-
switchInt(move _6) -> [0: bb6, otherwise: bb8];
45+
_3 = Le(const 13_u32, (_1.3: u32));
46+
switchInt(move _3) -> [0: bb1, otherwise: bb6];
4747
}
4848

4949
bb6: {
50-
_3 = Le(const 13_u32, (_1.3: u32));
51-
switchInt(move _3) -> [0: bb1, otherwise: bb7];
50+
_4 = Le((_1.3: u32), const 16_u32);
51+
switchInt(move _4) -> [0: bb1, otherwise: bb8];
5252
}
5353

5454
bb7: {
55-
_4 = Le((_1.3: u32), const 16_u32);
56-
switchInt(move _4) -> [0: bb1, otherwise: bb8];
55+
_6 = Le((_1.3: u32), const 9_u32);
56+
switchInt(move _6) -> [0: bb5, otherwise: bb8];
5757
}
5858

5959
bb8: {

tests/mir-opt/match_test.main.SimplifyCfg-initial.after.mir

+14-14
Original file line numberDiff line numberDiff line change
@@ -28,43 +28,43 @@ fn main() -> () {
2828
StorageLive(_3);
2929
PlaceMention(_1);
3030
_6 = Le(const 0_i32, _1);
31-
switchInt(move _6) -> [0: bb4, otherwise: bb1];
31+
switchInt(move _6) -> [0: bb3, otherwise: bb8];
3232
}
3333

3434
bb1: {
35-
_7 = Lt(_1, const 10_i32);
36-
switchInt(move _7) -> [0: bb4, otherwise: bb2];
35+
falseEdge -> [real: bb9, imaginary: bb4];
3736
}
3837

3938
bb2: {
40-
falseEdge -> [real: bb9, imaginary: bb6];
39+
_3 = const 3_i32;
40+
goto -> bb14;
4141
}
4242

4343
bb3: {
44-
_3 = const 3_i32;
45-
goto -> bb14;
44+
_4 = Le(const 10_i32, _1);
45+
switchInt(move _4) -> [0: bb5, otherwise: bb7];
4646
}
4747

4848
bb4: {
49-
_4 = Le(const 10_i32, _1);
50-
switchInt(move _4) -> [0: bb7, otherwise: bb5];
49+
falseEdge -> [real: bb12, imaginary: bb6];
5150
}
5251

5352
bb5: {
54-
_5 = Le(_1, const 20_i32);
55-
switchInt(move _5) -> [0: bb7, otherwise: bb6];
53+
switchInt(_1) -> [4294967295: bb6, otherwise: bb2];
5654
}
5755

5856
bb6: {
59-
falseEdge -> [real: bb12, imaginary: bb8];
57+
falseEdge -> [real: bb13, imaginary: bb2];
6058
}
6159

6260
bb7: {
63-
switchInt(_1) -> [4294967295: bb8, otherwise: bb3];
61+
_5 = Le(_1, const 20_i32);
62+
switchInt(move _5) -> [0: bb5, otherwise: bb4];
6463
}
6564

6665
bb8: {
67-
falseEdge -> [real: bb13, imaginary: bb3];
66+
_7 = Lt(_1, const 10_i32);
67+
switchInt(move _7) -> [0: bb3, otherwise: bb1];
6868
}
6969

7070
bb9: {
@@ -83,7 +83,7 @@ fn main() -> () {
8383

8484
bb11: {
8585
StorageDead(_9);
86-
falseEdge -> [real: bb3, imaginary: bb6];
86+
falseEdge -> [real: bb2, imaginary: bb4];
8787
}
8888

8989
bb12: {

0 commit comments

Comments
 (0)