Skip to content

Commit 625aff6

Browse files
committed
Auto merge of #119031 - Nadrieril:two-phase-match-lowering, r=<try>
[Experiment] Play with match lowering Match lowering to MIR has the reputation of being the most intricate piece of the compiler, and after banging my head on it for a bit I sure hope there isn't anything more intricate somewhere else. It's good quality code but I hope to unentangle it. This PR is me wrestling with it and asking `rustc-timer` for its opinion. r? `@ghost`
2 parents 5257aee + 6267474 commit 625aff6

17 files changed

+425
-433
lines changed

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

+194-166
Large diffs are not rendered by default.

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
113113
.cloned()
114114
.map(|flat_pat| {
115115
let mut candidate = Candidate::from_flat_pat(flat_pat, has_guard);
116-
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
117-
&*candidate.match_pairs
116+
if candidate.match_pairs.len() == 1
117+
&& let TestCase::Or { pats, .. } = &candidate.match_pairs[0].test_case
118118
{
119119
candidate.subcandidates = self.create_or_subcandidates(pats, has_guard);
120120
candidate.match_pairs.pop();

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

+101-183
Large diffs are not rendered by default.

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

+35-25
Original file line numberDiff line numberDiff line change
@@ -95,36 +95,41 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
9595

9696
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
9797
pub(in crate::build) fn new(
98-
mut place: PlaceBuilder<'tcx>,
98+
mut place_builder: PlaceBuilder<'tcx>,
9999
pattern: &'pat Pat<'tcx>,
100100
cx: &mut Builder<'_, 'tcx>,
101101
) -> MatchPair<'pat, 'tcx> {
102102
// Force the place type to the pattern's type.
103103
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
104-
if let Some(resolved) = place.resolve_upvar(cx) {
105-
place = resolved;
104+
if let Some(resolved) = place_builder.resolve_upvar(cx) {
105+
place_builder = resolved;
106106
}
107107

108108
// Only add the OpaqueCast projection if the given place is an opaque type and the
109109
// expected type from the pattern is not.
110-
let may_need_cast = match place.base() {
110+
let may_need_cast = match place_builder.base() {
111111
PlaceBase::Local(local) => {
112-
let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
112+
let ty =
113+
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
113114
ty != pattern.ty && ty.has_opaque_types()
114115
}
115116
_ => true,
116117
};
117118
if may_need_cast {
118-
place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
119+
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
119120
}
120121

122+
let place = place_builder.try_to_place(cx);
121123
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
122124
let mut subpairs = Vec::new();
123125
let test_case = match pattern.kind {
124126
PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
125-
PatKind::Or { ref pats } => TestCase::Or {
126-
pats: pats.iter().map(|pat| FlatPat::new(place.clone(), pat, cx)).collect(),
127-
},
127+
PatKind::Or { ref pats } => {
128+
let pats: Box<[_]> =
129+
pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
130+
let simple = pats.iter().all(|fpat| fpat.simple);
131+
TestCase::Or { pats, simple }
132+
}
128133

129134
PatKind::Range(ref range) => {
130135
if range.is_full_range(cx.tcx) == Some(true) {
@@ -142,13 +147,13 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
142147
..
143148
} => {
144149
// Apply the type ascription to the value at `match_pair.place`
145-
let ascription = place.try_to_place(cx).map(|source| super::Ascription {
150+
let ascription = place.map(|source| super::Ascription {
146151
annotation: annotation.clone(),
147152
source,
148153
variance,
149154
});
150155

151-
subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
156+
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
152157
TestCase::Irrefutable { ascription, binding: None }
153158
}
154159

@@ -161,7 +166,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
161166
ref subpattern,
162167
is_primary: _,
163168
} => {
164-
let binding = place.try_to_place(cx).map(|source| super::Binding {
169+
let binding = place.map(|source| super::Binding {
165170
span: pattern.span,
166171
source,
167172
var_id: var,
@@ -170,14 +175,14 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
170175

171176
if let Some(subpattern) = subpattern.as_ref() {
172177
// this is the `x @ P` case; have to keep matching against `P` now
173-
subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
178+
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
174179
}
175180
TestCase::Irrefutable { ascription: None, binding }
176181
}
177182

178183
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
179184
// Apply a type ascription for the inline constant to the value at `match_pair.place`
180-
let ascription = place.try_to_place(cx).map(|source| {
185+
let ascription = place.map(|source| {
181186
let span = pattern.span;
182187
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
183188
let args = ty::InlineConstArgs::new(
@@ -203,16 +208,16 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
203208
super::Ascription { annotation, source, variance: ty::Contravariant }
204209
});
205210

206-
subpairs.push(MatchPair::new(place.clone(), pattern, cx));
211+
subpairs.push(MatchPair::new(place_builder, pattern, cx));
207212
TestCase::Irrefutable { ascription, binding: None }
208213
}
209214

210215
PatKind::Array { ref prefix, ref slice, ref suffix } => {
211-
cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
216+
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
212217
default_irrefutable()
213218
}
214219
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
215-
cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
220+
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
216221

217222
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
218223
default_irrefutable()
@@ -225,7 +230,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
225230
}
226231

227232
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
228-
let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)`
233+
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
229234
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
230235

231236
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
@@ -247,19 +252,24 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
247252
}
248253

249254
PatKind::Leaf { ref subpatterns } => {
250-
subpairs = cx.field_match_pairs(place.clone(), subpatterns);
255+
subpairs = cx.field_match_pairs(place_builder, subpatterns);
251256
default_irrefutable()
252257
}
253258

254259
PatKind::Deref { ref subpattern } => {
255-
let place_builder = place.clone().deref();
256-
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
260+
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
257261
default_irrefutable()
258262
}
259263
};
260264

261265
MatchPair { place, test_case, subpairs, pattern }
262266
}
267+
268+
/// Whether this recursively contains no bindings or ascriptions.
269+
pub(super) fn is_simple(&self) -> bool {
270+
!matches!(self.test_case, TestCase::Or { simple: false, .. })
271+
&& self.subpairs.iter().all(|p| p.is_simple())
272+
}
263273
}
264274

265275
pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
@@ -283,7 +293,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
283293
for binding in &candidate.bindings {
284294
self.visit_binding(binding);
285295
}
286-
for match_pair in &candidate.match_pairs {
296+
for match_pair in candidate.match_pairs.values() {
287297
self.visit_match_pair(match_pair);
288298
}
289299
}
@@ -292,7 +302,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
292302
for binding in &flat_pat.bindings {
293303
self.visit_binding(binding);
294304
}
295-
for match_pair in &flat_pat.match_pairs {
305+
for match_pair in flat_pat.match_pairs.values() {
296306
self.visit_match_pair(match_pair);
297307
}
298308
}
@@ -304,8 +314,8 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
304314
}
305315
} else {
306316
// Insert a Shallow borrow of any place that is switched on.
307-
if let Some(resolved_place) = match_pair.place.try_to_place(self.cx) {
308-
self.fake_borrows.insert(resolved_place);
317+
if let Some(place) = match_pair.place {
318+
self.fake_borrows.insert(place);
309319
}
310320

311321
for subpair in &match_pair.subpairs {

tests/mir-opt/building/match_false_edges.full_tested_match.built.after.mir

+7-7
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn full_tested_match() -> () {
2828
_2 = Option::<i32>::Some(const 42_i32);
2929
PlaceMention(_2);
3030
_3 = discriminant(_2);
31-
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1];
31+
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
3232
}
3333

3434
bb1: {
@@ -37,20 +37,20 @@ fn full_tested_match() -> () {
3737
}
3838

3939
bb2: {
40-
_1 = (const 3_i32, const 3_i32);
41-
goto -> bb13;
40+
falseEdge -> [real: bb7, imaginary: bb3];
4241
}
4342

4443
bb3: {
45-
goto -> bb1;
44+
falseEdge -> [real: bb12, imaginary: bb5];
4645
}
4746

4847
bb4: {
49-
falseEdge -> [real: bb7, imaginary: bb5];
48+
goto -> bb1;
5049
}
5150

5251
bb5: {
53-
falseEdge -> [real: bb12, imaginary: bb2];
52+
_1 = (const 3_i32, const 3_i32);
53+
goto -> bb13;
5454
}
5555

5656
bb6: {
@@ -91,7 +91,7 @@ fn full_tested_match() -> () {
9191
bb11: {
9292
StorageDead(_7);
9393
StorageDead(_6);
94-
goto -> bb5;
94+
goto -> bb3;
9595
}
9696

9797
bb12: {

tests/mir-opt/building/match_false_edges.full_tested_match2.built.after.mir

+11-11
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn full_tested_match2() -> () {
2828
_2 = Option::<i32>::Some(const 42_i32);
2929
PlaceMention(_2);
3030
_3 = discriminant(_2);
31-
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1];
31+
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
3232
}
3333

3434
bb1: {
@@ -37,18 +37,10 @@ fn full_tested_match2() -> () {
3737
}
3838

3939
bb2: {
40-
falseEdge -> [real: bb12, imaginary: bb5];
40+
falseEdge -> [real: bb7, imaginary: bb5];
4141
}
4242

4343
bb3: {
44-
goto -> bb1;
45-
}
46-
47-
bb4: {
48-
falseEdge -> [real: bb7, imaginary: bb2];
49-
}
50-
51-
bb5: {
5244
StorageLive(_9);
5345
_9 = ((_2 as Some).0: i32);
5446
StorageLive(_10);
@@ -59,6 +51,14 @@ fn full_tested_match2() -> () {
5951
goto -> bb13;
6052
}
6153

54+
bb4: {
55+
goto -> bb1;
56+
}
57+
58+
bb5: {
59+
falseEdge -> [real: bb12, imaginary: bb3];
60+
}
61+
6262
bb6: {
6363
goto -> bb1;
6464
}
@@ -97,7 +97,7 @@ fn full_tested_match2() -> () {
9797
bb11: {
9898
StorageDead(_7);
9999
StorageDead(_6);
100-
falseEdge -> [real: bb5, imaginary: bb2];
100+
falseEdge -> [real: bb3, imaginary: bb5];
101101
}
102102

103103
bb12: {

tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
StorageDead(_5);
3131
StorageDead(_4);
3232
_8 = discriminant((_3.0: std::option::Option<u32>));
33-
- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1];
33+
- switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
3434
+ StorageLive(_11);
3535
+ _11 = discriminant((_3.1: std::option::Option<u32>));
3636
+ StorageLive(_12);
@@ -48,12 +48,12 @@
4848

4949
bb2: {
5050
- _6 = discriminant((_3.1: std::option::Option<u32>));
51-
- switchInt(move _6) -> [0: bb5, otherwise: bb1];
51+
- switchInt(move _6) -> [1: bb4, otherwise: bb1];
5252
- }
5353
-
5454
- bb3: {
5555
- _7 = discriminant((_3.1: std::option::Option<u32>));
56-
- switchInt(move _7) -> [1: bb4, otherwise: bb1];
56+
- switchInt(move _7) -> [0: bb5, otherwise: bb1];
5757
- }
5858
-
5959
- bb4: {

tests/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff

+6-6
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
StorageDead(_5);
3737
StorageDead(_4);
3838
_8 = discriminant((_3.0: std::option::Option<u32>));
39-
switchInt(move _8) -> [0: bb2, 1: bb4, otherwise: bb1];
39+
switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
4040
}
4141

4242
bb1: {
@@ -45,17 +45,17 @@
4545

4646
bb2: {
4747
_6 = discriminant((_3.1: std::option::Option<u32>));
48-
switchInt(move _6) -> [0: bb3, 1: bb7, otherwise: bb1];
48+
switchInt(move _6) -> [0: bb6, 1: bb5, otherwise: bb1];
4949
}
5050

5151
bb3: {
52-
_0 = const 3_u32;
53-
goto -> bb8;
52+
_7 = discriminant((_3.1: std::option::Option<u32>));
53+
switchInt(move _7) -> [0: bb4, 1: bb7, otherwise: bb1];
5454
}
5555

5656
bb4: {
57-
_7 = discriminant((_3.1: std::option::Option<u32>));
58-
switchInt(move _7) -> [0: bb6, 1: bb5, otherwise: bb1];
57+
_0 = const 3_u32;
58+
goto -> bb8;
5959
}
6060

6161
bb5: {

tests/mir-opt/match_arm_scopes.complicated_match.panic-abort.SimplifyCfg-initial.after-ElaborateDrops.after.diff

+8-7
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@
4242
}
4343

4444
bb2: {
45-
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
45+
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
4646
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
4747
}
4848

4949
bb3: {
50+
- falseEdge -> [real: bb20, imaginary: bb4];
51+
- }
52+
-
53+
- bb4: {
5054
StorageLive(_15);
5155
_15 = (_2.1: bool);
5256
StorageLive(_16);
@@ -55,19 +59,16 @@
5559
+ goto -> bb16;
5660
}
5761

58-
bb4: {
59-
- falseEdge -> [real: bb20, imaginary: bb3];
60-
- }
61-
-
6262
- bb5: {
63-
- falseEdge -> [real: bb13, imaginary: bb4];
63+
- falseEdge -> [real: bb13, imaginary: bb3];
6464
- }
6565
-
6666
- bb6: {
6767
- falseEdge -> [real: bb8, imaginary: bb5];
6868
- }
6969
-
7070
- bb7: {
71+
+ bb4: {
7172
_0 = const 1_i32;
7273
- drop(_7) -> [return: bb18, unwind: bb25];
7374
+ drop(_7) -> [return: bb15, unwind: bb22];
@@ -183,7 +184,7 @@
183184
StorageDead(_12);
184185
StorageDead(_8);
185186
StorageDead(_6);
186-
- falseEdge -> [real: bb2, imaginary: bb4];
187+
- falseEdge -> [real: bb2, imaginary: bb3];
187188
+ goto -> bb2;
188189
}
189190

0 commit comments

Comments
 (0)