Skip to content

Commit af9b9e4

Browse files
committed
MatchBranchSimplification: avoid intermediate vec allocation
1 parent 1fe2e29 commit af9b9e4

File tree

2 files changed

+46
-38
lines changed

2 files changed

+46
-38
lines changed

src/librustc_index/vec.rs

+11
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,17 @@ impl<I: Idx, T> IndexVec<I, T> {
669669
}
670670
}
671671

672+
/// Returns mutable references to three distinct elements or panics otherwise.
673+
#[inline]
674+
pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
675+
let (ai, bi, ci) = (a.index(), b.index(), c.index());
676+
assert!(ai != bi && bi != ci && ci != ai);
677+
let len = self.raw.len();
678+
assert!(ai < len && bi < len && ci < len);
679+
let ptr = self.raw.as_mut_ptr();
680+
unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) }
681+
}
682+
672683
pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
673684
IndexVec { raw: self.raw, _marker: PhantomData }
674685
}

src/librustc_mir/transform/match_branches.rs

+35-38
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
4848
ref targets,
4949
ref values,
5050
..
51-
} if targets.len() == 2 && values.len() == 1 => {
51+
} if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => {
5252
(place, values[0], switch_ty, targets[0], targets[1])
5353
}
5454
// Only optimize switch int statements
@@ -89,48 +89,45 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
8989
// Take ownership of items now that we know we can optimize.
9090
let discr = discr.clone();
9191

92-
let new_stmts = first_stmts
93-
.iter()
94-
.zip(scnd_stmts.iter())
95-
.map(|(f, s)| {
96-
match (&f.kind, &s.kind) {
97-
(f_s, s_s) if f_s == s_s => (*f).clone(),
92+
// We already checked that first and second are different blocks,
93+
// and bb_idx has a different terminator from both of them.
94+
let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
9895

99-
(
100-
StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
101-
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
102-
) => {
103-
// From earlier loop we know that we are dealing with bool constants only:
104-
let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap();
105-
let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
106-
if f_b == s_b {
107-
// Same value in both blocks. Use statement as is.
108-
(*f).clone()
109-
} else {
110-
// Different value between blocks. Make value conditional on switch condition.
111-
let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
112-
let const_cmp = Operand::const_from_scalar(
113-
tcx,
114-
switch_ty,
115-
crate::interpret::Scalar::from_uint(val, size),
116-
rustc_span::DUMMY_SP,
117-
);
118-
let op = if f_b { BinOp::Eq } else { BinOp::Ne };
119-
let rhs =
120-
Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp);
121-
Statement {
122-
source_info: f.source_info,
123-
kind: StatementKind::Assign(box (*lhs, rhs)),
124-
}
96+
let new_stmts = first.statements.iter().zip(second.statements.iter()).map(|(f, s)| {
97+
match (&f.kind, &s.kind) {
98+
(f_s, s_s) if f_s == s_s => (*f).clone(),
99+
100+
(
101+
StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
102+
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
103+
) => {
104+
// From earlier loop we know that we are dealing with bool constants only:
105+
let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap();
106+
let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
107+
if f_b == s_b {
108+
// Same value in both blocks. Use statement as is.
109+
(*f).clone()
110+
} else {
111+
// Different value between blocks. Make value conditional on switch condition.
112+
let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
113+
let const_cmp = Operand::const_from_scalar(
114+
tcx,
115+
switch_ty,
116+
crate::interpret::Scalar::from_uint(val, size),
117+
rustc_span::DUMMY_SP,
118+
);
119+
let op = if f_b { BinOp::Eq } else { BinOp::Ne };
120+
let rhs = Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp);
121+
Statement {
122+
source_info: f.source_info,
123+
kind: StatementKind::Assign(box (*lhs, rhs)),
125124
}
126125
}
127-
128-
_ => unreachable!(),
129126
}
130-
})
131-
.collect::<Vec<_>>();
132127

133-
let (from, first) = bbs.pick2_mut(bb_idx, first);
128+
_ => unreachable!(),
129+
}
130+
});
134131
from.statements.extend(new_stmts);
135132
from.terminator_mut().kind = first.terminator().kind.clone();
136133
}

0 commit comments

Comments
 (0)