Skip to content

Commit

Permalink
Auto merge of rust-lang#119031 - Nadrieril:two-phase-match-lowering, …
Browse files Browse the repository at this point in the history
…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`
  • Loading branch information
bors committed Mar 2, 2024
2 parents 5257aee + 6267474 commit 625aff6
Show file tree
Hide file tree
Showing 17 changed files with 425 additions and 433 deletions.
360 changes: 194 additions & 166 deletions compiler/rustc_mir_build/src/build/matches/mod.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/build/matches/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
.cloned()
.map(|flat_pat| {
let mut candidate = Candidate::from_flat_pat(flat_pat, has_guard);
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
&*candidate.match_pairs
if candidate.match_pairs.len() == 1
&& let TestCase::Or { pats, .. } = &candidate.match_pairs[0].test_case
{
candidate.subcandidates = self.create_or_subcandidates(pats, has_guard);
candidate.match_pairs.pop();
Expand Down
284 changes: 101 additions & 183 deletions compiler/rustc_mir_build/src/build/matches/test.rs

Large diffs are not rendered by default.

60 changes: 35 additions & 25 deletions compiler/rustc_mir_build/src/build/matches/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,36 +95,41 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

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

// Only add the OpaqueCast projection if the given place is an opaque type and the
// expected type from the pattern is not.
let may_need_cast = match place.base() {
let may_need_cast = match place_builder.base() {
PlaceBase::Local(local) => {
let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty;
let ty =
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
ty != pattern.ty && ty.has_opaque_types()
}
_ => true,
};
if may_need_cast {
place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}

let place = place_builder.try_to_place(cx);
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
let mut subpairs = Vec::new();
let test_case = match pattern.kind {
PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
PatKind::Or { ref pats } => TestCase::Or {
pats: pats.iter().map(|pat| FlatPat::new(place.clone(), pat, cx)).collect(),
},
PatKind::Or { ref pats } => {
let pats: Box<[_]> =
pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect();
let simple = pats.iter().all(|fpat| fpat.simple);
TestCase::Or { pats, simple }
}

PatKind::Range(ref range) => {
if range.is_full_range(cx.tcx) == Some(true) {
Expand All @@ -142,13 +147,13 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
..
} => {
// Apply the type ascription to the value at `match_pair.place`
let ascription = place.try_to_place(cx).map(|source| super::Ascription {
let ascription = place.map(|source| super::Ascription {
annotation: annotation.clone(),
source,
variance,
});

subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
TestCase::Irrefutable { ascription, binding: None }
}

Expand All @@ -161,7 +166,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
ref subpattern,
is_primary: _,
} => {
let binding = place.try_to_place(cx).map(|source| super::Binding {
let binding = place.map(|source| super::Binding {
span: pattern.span,
source,
var_id: var,
Expand All @@ -170,14 +175,14 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {

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

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

subpairs.push(MatchPair::new(place.clone(), pattern, cx));
subpairs.push(MatchPair::new(place_builder, pattern, cx));
TestCase::Irrefutable { ascription, binding: None }
}

PatKind::Array { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
default_irrefutable()
}
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);

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

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

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

PatKind::Leaf { ref subpatterns } => {
subpairs = cx.field_match_pairs(place.clone(), subpatterns);
subpairs = cx.field_match_pairs(place_builder, subpatterns);
default_irrefutable()
}

PatKind::Deref { ref subpattern } => {
let place_builder = place.clone().deref();
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
default_irrefutable()
}
};

MatchPair { place, test_case, subpairs, pattern }
}

/// Whether this recursively contains no bindings or ascriptions.
pub(super) fn is_simple(&self) -> bool {
!matches!(self.test_case, TestCase::Or { simple: false, .. })
&& self.subpairs.iter().all(|p| p.is_simple())
}
}

pub(super) struct FakeBorrowCollector<'a, 'b, 'tcx> {
Expand All @@ -283,7 +293,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
for binding in &candidate.bindings {
self.visit_binding(binding);
}
for match_pair in &candidate.match_pairs {
for match_pair in candidate.match_pairs.values() {
self.visit_match_pair(match_pair);
}
}
Expand All @@ -292,7 +302,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
for binding in &flat_pat.bindings {
self.visit_binding(binding);
}
for match_pair in &flat_pat.match_pairs {
for match_pair in flat_pat.match_pairs.values() {
self.visit_match_pair(match_pair);
}
}
Expand All @@ -304,8 +314,8 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
}
} else {
// Insert a Shallow borrow of any place that is switched on.
if let Some(resolved_place) = match_pair.place.try_to_place(self.cx) {
self.fake_borrows.insert(resolved_place);
if let Some(place) = match_pair.place {
self.fake_borrows.insert(place);
}

for subpair in &match_pair.subpairs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn full_tested_match() -> () {
_2 = Option::<i32>::Some(const 42_i32);
PlaceMention(_2);
_3 = discriminant(_2);
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1];
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
}

bb1: {
Expand All @@ -37,20 +37,20 @@ fn full_tested_match() -> () {
}

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

bb3: {
goto -> bb1;
falseEdge -> [real: bb12, imaginary: bb5];
}

bb4: {
falseEdge -> [real: bb7, imaginary: bb5];
goto -> bb1;
}

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

bb6: {
Expand Down Expand Up @@ -91,7 +91,7 @@ fn full_tested_match() -> () {
bb11: {
StorageDead(_7);
StorageDead(_6);
goto -> bb5;
goto -> bb3;
}

bb12: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn full_tested_match2() -> () {
_2 = Option::<i32>::Some(const 42_i32);
PlaceMention(_2);
_3 = discriminant(_2);
switchInt(move _3) -> [0: bb2, 1: bb4, otherwise: bb1];
switchInt(move _3) -> [0: bb5, 1: bb2, otherwise: bb1];
}

bb1: {
Expand All @@ -37,18 +37,10 @@ fn full_tested_match2() -> () {
}

bb2: {
falseEdge -> [real: bb12, imaginary: bb5];
falseEdge -> [real: bb7, imaginary: bb5];
}

bb3: {
goto -> bb1;
}

bb4: {
falseEdge -> [real: bb7, imaginary: bb2];
}

bb5: {
StorageLive(_9);
_9 = ((_2 as Some).0: i32);
StorageLive(_10);
Expand All @@ -59,6 +51,14 @@ fn full_tested_match2() -> () {
goto -> bb13;
}

bb4: {
goto -> bb1;
}

bb5: {
falseEdge -> [real: bb12, imaginary: bb3];
}

bb6: {
goto -> bb1;
}
Expand Down Expand Up @@ -97,7 +97,7 @@ fn full_tested_match2() -> () {
bb11: {
StorageDead(_7);
StorageDead(_6);
falseEdge -> [real: bb5, imaginary: bb2];
falseEdge -> [real: bb3, imaginary: bb5];
}

bb12: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
StorageDead(_5);
StorageDead(_4);
_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);
+ _11 = discriminant((_3.1: std::option::Option<u32>));
+ StorageLive(_12);
Expand All @@ -48,12 +48,12 @@

bb2: {
- _6 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _6) -> [0: bb5, otherwise: bb1];
- switchInt(move _6) -> [1: bb4, otherwise: bb1];
- }
-
- bb3: {
- _7 = discriminant((_3.1: std::option::Option<u32>));
- switchInt(move _7) -> [1: bb4, otherwise: bb1];
- switchInt(move _7) -> [0: bb5, otherwise: bb1];
- }
-
- bb4: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
StorageDead(_5);
StorageDead(_4);
_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: {
Expand All @@ -45,17 +45,17 @@

bb2: {
_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: {
_0 = const 3_u32;
goto -> bb8;
_7 = discriminant((_3.1: std::option::Option<u32>));
switchInt(move _7) -> [0: bb4, 1: bb7, otherwise: bb1];
}

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

bb5: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,15 @@
}

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

bb3: {
- falseEdge -> [real: bb20, imaginary: bb4];
- }
-
- bb4: {
StorageLive(_15);
_15 = (_2.1: bool);
StorageLive(_16);
Expand All @@ -55,19 +59,16 @@
+ goto -> bb16;
}

bb4: {
- falseEdge -> [real: bb20, imaginary: bb3];
- }
-
- bb5: {
- falseEdge -> [real: bb13, imaginary: bb4];
- falseEdge -> [real: bb13, imaginary: bb3];
- }
-
- bb6: {
- falseEdge -> [real: bb8, imaginary: bb5];
- }
-
- bb7: {
+ bb4: {
_0 = const 1_i32;
- drop(_7) -> [return: bb18, unwind: bb25];
+ drop(_7) -> [return: bb15, unwind: bb22];
Expand Down Expand Up @@ -183,7 +184,7 @@
StorageDead(_12);
StorageDead(_8);
StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb4];
- falseEdge -> [real: bb2, imaginary: bb3];
+ goto -> bb2;
}

Expand Down
Loading

0 comments on commit 625aff6

Please sign in to comment.