Skip to content

Commit da954df

Browse files
committed
valtree simplification
1 parent 0df0662 commit da954df

File tree

2 files changed

+116
-7
lines changed

2 files changed

+116
-7
lines changed

compiler/rustc_middle/src/arena.rs

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ macro_rules! arena_types {
114114
[decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
115115
[] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
116116
[] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
117+
[] pats2: rustc_middle::thir::Pat<'tcx>,
117118
]);
118119
)
119120
}

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

+115-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_middle::mir::*;
22
use rustc_middle::thir::{self, *};
33
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
4+
use rustc_span::Span;
45

56
use crate::builder::Builder;
67
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
@@ -27,12 +28,100 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2728
.collect()
2829
}
2930

31+
// We don't consider an empty subslice as a constant pattern subslice.
32+
fn is_constant_pattern_subslice(&self, subslice: &[Box<Pat<'tcx>>]) -> bool {
33+
!subslice.is_empty() && subslice.iter().all(|p| self.is_constant_pattern(p))
34+
}
35+
36+
// TODO: expand beyond u8
37+
fn is_constant_pattern(&self, pat: &Pat<'tcx>) -> bool {
38+
if let PatKind::Constant { value } = pat.kind
39+
&& let Const::Ty(_, const_) = value
40+
&& let ty::ConstKind::Value(ty, valtree) = const_.kind()
41+
&& self.tcx.types.u8 == ty
42+
&& matches!(valtree, ty::ValTree::Leaf(_))
43+
{
44+
true
45+
} else {
46+
false
47+
}
48+
}
49+
50+
fn extract_leaf(&self, pat: &Pat<'tcx>) -> ty::ValTree<'tcx> {
51+
if let PatKind::Constant { value } = pat.kind
52+
&& let Const::Ty(_, const_) = value
53+
&& let ty::ConstKind::Value(_, valtree) = const_.kind()
54+
&& matches!(valtree, ty::ValTree::Leaf(_))
55+
{
56+
valtree
57+
} else {
58+
unreachable!()
59+
}
60+
}
61+
62+
// This must only be called after ensuring that the subslice consists of only constant
63+
// patterns, or it will panic.
64+
fn simplify_const_pattern_slice_into_valtree(
65+
&self,
66+
subslice: &[Box<Pat<'tcx>>],
67+
) -> ty::ValTree<'tcx> {
68+
let leaves = subslice.iter().map(|p| self.extract_leaf(p));
69+
let interned = self.tcx.arena.alloc_from_iter(leaves);
70+
ty::ValTree::Branch(interned)
71+
}
72+
73+
fn valtree_to_match_pair<'pat>(
74+
&mut self,
75+
base_pat_ty: Ty<'tcx>,
76+
span: Span,
77+
subslice_len: u64,
78+
valtree: ty::ValTree<'tcx>,
79+
place: PlaceBuilder<'tcx>,
80+
elem_ty: Ty<'tcx>,
81+
) -> MatchPairTree<'pat, 'tcx> {
82+
let tcx = self.tcx;
83+
let (const_ty, pat_ty) = if base_pat_ty.is_slice() {
84+
(
85+
Ty::new_imm_ref(
86+
tcx,
87+
tcx.lifetimes.re_erased,
88+
Ty::new_array(tcx, elem_ty, subslice_len),
89+
),
90+
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, Ty::new_slice(tcx, elem_ty)),
91+
)
92+
} else {
93+
//let arr_ty = Ty::new_array(tcx, elem_ty, subslice_len);
94+
let arr_ty = Ty::new_slice(tcx, elem_ty);
95+
let pat_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, arr_ty);
96+
(arr_ty, arr_ty)
97+
};
98+
99+
let r#const = ty::Const::new(tcx, ty::ConstKind::Value(const_ty, valtree));
100+
let r#const2 = Const::Ty(const_ty, r#const);
101+
102+
let pattern = tcx.arena.alloc(Pat {
103+
ty: pat_ty,
104+
span,
105+
kind: PatKind::Constant { value: Const::Ty(const_ty, r#const) },
106+
});
107+
108+
let test_case = TestCase::Constant { value: r#const2 };
109+
110+
MatchPairTree {
111+
place: Some(place.to_place(self)),
112+
test_case,
113+
subpairs: Vec::new(),
114+
pattern,
115+
}
116+
}
117+
30118
/// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an
31119
/// array pattern or slice pattern, and adds those trees to `match_pairs`.
32120
///
33121
/// Used internally by [`MatchPairTree::for_pattern`].
34122
fn prefix_slice_suffix<'pat>(
35123
&mut self,
124+
base_pat: &'pat Pat<'tcx>,
36125
match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>,
37126
place: &PlaceBuilder<'tcx>,
38127
prefix: &'pat [Box<Pat<'tcx>>],
@@ -54,11 +143,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
54143
((prefix.len() + suffix.len()).try_into().unwrap(), false)
55144
};
56145

57-
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
58-
let elem =
59-
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
60-
MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self)
61-
}));
146+
// Here we try to special-case constant pattern subslices into valtrees to generate
147+
// nicer MIR.
148+
// Try to perform simplification of a constant pattern slice `prefix` sequence into
149+
// a valtree.
150+
if self.is_constant_pattern_subslice(prefix) {
151+
let elem_ty = prefix[0].ty;
152+
let prefix_valtree = self.simplify_const_pattern_slice_into_valtree(prefix);
153+
// FIXME(jieyouxu): triple check these place calculations!
154+
let match_pair = self.valtree_to_match_pair(
155+
base_pat.ty,
156+
base_pat.span,
157+
prefix.len() as u64,
158+
prefix_valtree,
159+
place.base().into(),
160+
elem_ty,
161+
);
162+
match_pairs.push(match_pair);
163+
} else {
164+
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
165+
let elem =
166+
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
167+
MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self)
168+
}));
169+
}
62170

63171
if let Some(subslice_pat) = opt_slice {
64172
let suffix_len = suffix.len() as u64;
@@ -192,11 +300,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
192300
}
193301

194302
PatKind::Array { ref prefix, ref slice, ref suffix } => {
195-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
303+
cx.prefix_slice_suffix(pattern, &mut subpairs, &place_builder, prefix, slice, suffix);
196304
default_irrefutable()
197305
}
198306
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
199-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
307+
cx.prefix_slice_suffix(pattern, &mut subpairs, &place_builder, prefix, slice, suffix);
200308

201309
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
202310
default_irrefutable()

0 commit comments

Comments
 (0)