diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 63f63133a2c95..2420f82c0418d 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -680,6 +680,17 @@ impl IndexVec { } } + /// Returns mutable references to three distinct elements or panics otherwise. + #[inline] + pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) { + let (ai, bi, ci) = (a.index(), b.index(), c.index()); + assert!(ai != bi && bi != ci && ci != ai); + let len = self.raw.len(); + assert!(ai < len && bi < len && ci < len); + let ptr = self.raw.as_mut_ptr(); + unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) } + } + pub fn convert_index_type(self) -> IndexVec { IndexVec { raw: self.raw, _marker: PhantomData } } diff --git a/src/librustc_mir/transform/match_branches.rs b/src/librustc_mir/transform/match_branches.rs index 74da6d5e629b3..c1d574d6ef290 100644 --- a/src/librustc_mir/transform/match_branches.rs +++ b/src/librustc_mir/transform/match_branches.rs @@ -4,10 +4,37 @@ use rustc_middle::ty::TyCtxt; pub struct MatchBranchSimplification; -// What's the intent of this pass? -// If one block is found that switches between blocks which both go to the same place -// AND both of these blocks set a similar const in their -> -// condense into 1 block based on discriminant AND goto the destination afterwards +/// If a source block is found that switches between two blocks that are exactly +/// the same modulo const bool assignments (e.g., one assigns true another false +/// to the same place), merge a target block statements into the source block, +/// using Eq / Ne comparison with switch value where const bools value differ. +/// +/// For example: +/// +/// ```rust +/// bb0: { +/// switchInt(move _3) -> [42_isize: bb1, otherwise: bb2]; +/// } +/// +/// bb1: { +/// _2 = const true; +/// goto -> bb3; +/// } +/// +/// bb2: { +/// _2 = const false; +/// goto -> bb3; +/// } +/// ``` +/// +/// into: +/// +/// ```rust +/// bb0: { +/// _2 = Eq(move _3, const 42_isize); +/// goto -> bb3; +/// } +/// ``` impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { @@ -16,12 +43,12 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { 'outer: for bb_idx in bbs.indices() { let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind { TerminatorKind::SwitchInt { - discr: Operand::Move(ref place), + discr: Operand::Copy(ref place) | Operand::Move(ref place), switch_ty, ref targets, ref values, .. - } if targets.len() == 2 && values.len() == 1 => { + } if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => { (place, values[0], switch_ty, targets[0], targets[1]) } // Only optimize switch int statements @@ -42,49 +69,64 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) { match (&f.kind, &s.kind) { - // If two statements are exactly the same just ignore them. - (f_s, s_s) if f_s == s_s => (), + // If two statements are exactly the same, we can optimize. + (f_s, s_s) if f_s == s_s => {} + // If two statements are const bool assignments to the same place, we can optimize. ( StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), - ) if lhs_f == lhs_s => { - if let Some(f_c) = f_c.literal.try_eval_bool(tcx, param_env) { - // This should also be a bool because it's writing to the same place - let s_c = s_c.literal.try_eval_bool(tcx, param_env).unwrap(); - if f_c != s_c { - // have to check this here because f_c & s_c might have - // different spans. - continue; - } - } - continue 'outer; - } - // If there are not exclusively assignments, then ignore this + ) if lhs_f == lhs_s + && f_c.literal.ty.is_bool() + && s_c.literal.ty.is_bool() + && f_c.literal.try_eval_bool(tcx, param_env).is_some() + && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {} + + // Otherwise we cannot optimize. Try another block. _ => continue 'outer, } } - // Take owenership of items now that we know we can optimize. + // Take ownership of items now that we know we can optimize. let discr = discr.clone(); - let (from, first) = bbs.pick2_mut(bb_idx, first); - let new_stmts = first.statements.iter().cloned().map(|mut s| { - if let StatementKind::Assign(box (_, ref mut rhs)) = s.kind { - if let Rvalue::Use(Operand::Constant(c)) = rhs { - let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; - let const_cmp = Operand::const_from_scalar( - tcx, - switch_ty, - crate::interpret::Scalar::from_uint(val, size), - rustc_span::DUMMY_SP, - ); - if let Some(c) = c.literal.try_eval_bool(tcx, param_env) { - let op = if c { BinOp::Eq } else { BinOp::Ne }; - *rhs = Rvalue::BinaryOp(op, Operand::Move(discr), const_cmp); + // We already checked that first and second are different blocks, + // and bb_idx has a different terminator from both of them. + let (from, first, second) = bbs.pick3_mut(bb_idx, first, second); + + let new_stmts = first.statements.iter().zip(second.statements.iter()).map(|(f, s)| { + match (&f.kind, &s.kind) { + (f_s, s_s) if f_s == s_s => (*f).clone(), + + ( + StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), + ) => { + // From earlier loop we know that we are dealing with bool constants only: + let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap(); + let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap(); + if f_b == s_b { + // Same value in both blocks. Use statement as is. + (*f).clone() + } else { + // Different value between blocks. Make value conditional on switch condition. + let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; + let const_cmp = Operand::const_from_scalar( + tcx, + switch_ty, + crate::interpret::Scalar::from_uint(val, size), + rustc_span::DUMMY_SP, + ); + let op = if f_b { BinOp::Eq } else { BinOp::Ne }; + let rhs = Rvalue::BinaryOp(op, Operand::Copy(discr.clone()), const_cmp); + Statement { + source_info: f.source_info, + kind: StatementKind::Assign(box (*lhs, rhs)), + } } } + + _ => unreachable!(), } - s }); from.statements.extend(new_stmts); from.terminator_mut().kind = first.terminator().kind.clone(); diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit new file mode 100644 index 0000000000000..968890e3a298c --- /dev/null +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit @@ -0,0 +1,156 @@ +- // MIR for `bar` before MatchBranchSimplification ++ // MIR for `bar` after MatchBranchSimplification + + fn bar(_1: i32) -> (bool, bool, bool, bool) { + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + scope 1 { + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + scope 2 { + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + scope 3 { + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + scope 4 { + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + } + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 ++ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 ++ // ty::Const ++ // + ty: i32 ++ // + val: Value(Scalar(0x00000007)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1 ++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) } ++ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 ++ // ty::Const ++ // + ty: i32 ++ // + val: Value(Scalar(0x00000007)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1 ++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) } ++ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x00)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } ++ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x01)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } ++ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 + } + + bb1: { + _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:26:17: 26:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:27:17: 27:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:28:17: 28:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:29:17: 29:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + } + + bb2: { + _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:19:17: 19:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:20:17: 20:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + } + + bb3: { + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2 + } + } + diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit new file mode 100644 index 0000000000000..968890e3a298c --- /dev/null +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit @@ -0,0 +1,156 @@ +- // MIR for `bar` before MatchBranchSimplification ++ // MIR for `bar` after MatchBranchSimplification + + fn bar(_1: i32) -> (bool, bool, bool, bool) { + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + scope 1 { + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + scope 2 { + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + scope 3 { + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + scope 4 { + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + } + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 ++ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 ++ // ty::Const ++ // + ty: i32 ++ // + val: Value(Scalar(0x00000007)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1 ++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) } ++ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 ++ // ty::Const ++ // + ty: i32 ++ // + val: Value(Scalar(0x00000007)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1 ++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000007)) } ++ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x00)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } ++ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 ++ // ty::Const ++ // + ty: bool ++ // + val: Value(Scalar(0x01)) ++ // mir::Constant ++ // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21 ++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } ++ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 + } + + bb1: { + _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:26:17: 26:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:27:17: 27:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:28:17: 28:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:29:17: 29:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + } + + bb2: { + _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:19:17: 19:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:20:17: 20:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:21:17: 21:22 + // + literal: Const { ty: bool, val: Value(Scalar(0x00)) } + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:22:17: 22:21 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + } + + bb3: { + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2 + } + } + diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit index df94c897e92f8..a33db001f4438 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit @@ -2,23 +2,23 @@ + // MIR for `foo` after MatchBranchSimplification fn foo(_1: std::option::Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25 + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 -+ _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 ++ _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // ty::Const + // + ty: isize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1 + // + literal: Const { ty: isize, val: Value(Scalar(0x00000000)) } -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 } bb1: { @@ -44,23 +44,23 @@ } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6 + switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6 + // + span: $DIR/matches_reduce_branches.rs:6:5: 8:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6 + goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 } bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit index 06849b4a5d983..3eb5b01fbf496 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit @@ -2,23 +2,23 @@ + // MIR for `foo` after MatchBranchSimplification fn foo(_1: std::option::Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:4:8: 4:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:4:25: 4:25 + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 -+ _2 = Eq(move _3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 ++ _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // ty::Const + // + ty: isize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/matches_reduce_branches.rs:1:1: 1:1 + // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000000)) } -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:5:22: 5:26 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 } bb1: { @@ -44,23 +44,23 @@ } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6 + switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/matches_reduce_branches.rs:5:5: 7:6 + // + span: $DIR/matches_reduce_branches.rs:6:5: 8:6 // + literal: Const { ty: (), val: Value(Scalar()) } - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:5:5: 7:6 + goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 } bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:8:1: 8:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:8:2: 8:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs index 91b6bfc836bd4..ebc88d2fbd1da 100644 --- a/src/test/mir-opt/matches_reduce_branches.rs +++ b/src/test/mir-opt/matches_reduce_branches.rs @@ -1,5 +1,6 @@ // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff +// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff fn foo(bar: Option<()>) { if matches!(bar, None) { @@ -7,7 +8,35 @@ fn foo(bar: Option<()>) { } } +fn bar(i: i32) -> (bool, bool, bool, bool) { + let a; + let b; + let c; + let d; + + match i { + 7 => { + a = false; + b = true; + c = false; + d = true; + () + } + _ => { + a = true; + b = false; + c = false; + d = true; + () + } + }; + + (a, b, c, d) +} + + fn main() { let _ = foo(None); let _ = foo(Some(())); + let _ = bar(0); } diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit new file mode 100644 index 0000000000000..c41bd999dc9fc --- /dev/null +++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit @@ -0,0 +1,40 @@ +- // MIR for `exhaustive_match` before MatchBranchSimplification ++ // MIR for `exhaustive_match` after MatchBranchSimplification + + fn exhaustive_match(_1: E) -> u8 { + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:11:25: 11:26 + let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:11:34: 11:36 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:13:9: 13:13 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:13:9: 13:13 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:13:9: 13:13 + } + + bb1: { + _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_u8.rs:14:17: 14:18 + // + literal: Const { ty: u8, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6 + } + + bb2: { + _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_u8.rs:13:17: 13:18 + // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6 + } + + bb3: { + return; // scope 0 at $DIR/matches_u8.rs:16:2: 16:2 + } + } + diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit new file mode 100644 index 0000000000000..c41bd999dc9fc --- /dev/null +++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit @@ -0,0 +1,40 @@ +- // MIR for `exhaustive_match` before MatchBranchSimplification ++ // MIR for `exhaustive_match` after MatchBranchSimplification + + fn exhaustive_match(_1: E) -> u8 { + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:11:25: 11:26 + let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:11:34: 11:36 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:13:9: 13:13 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:13:9: 13:13 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:13:9: 13:13 + } + + bb1: { + _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_u8.rs:14:17: 14:18 + // + literal: Const { ty: u8, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6 + } + + bb2: { + _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_u8.rs:13:17: 13:18 + // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6 + } + + bb3: { + return; // scope 0 at $DIR/matches_u8.rs:16:2: 16:2 + } + } + diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit new file mode 100644 index 0000000000000..2c4bbc8095e9a --- /dev/null +++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit @@ -0,0 +1,40 @@ +- // MIR for `exhaustive_match_i8` before MatchBranchSimplification ++ // MIR for `exhaustive_match_i8` after MatchBranchSimplification + + fn exhaustive_match_i8(_1: E) -> i8 { + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:19:28: 19:29 + let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:19:37: 19:39 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:21:9: 21:13 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:21:9: 21:13 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:21:9: 21:13 + } + + bb1: { + _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18 + // ty::Const + // + ty: i8 + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_u8.rs:22:17: 22:18 + // + literal: Const { ty: i8, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6 + } + + bb2: { + _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18 + // ty::Const + // + ty: i8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_u8.rs:21:17: 21:18 + // + literal: Const { ty: i8, val: Value(Scalar(0x00)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6 + } + + bb3: { + return; // scope 0 at $DIR/matches_u8.rs:24:2: 24:2 + } + } + diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit new file mode 100644 index 0000000000000..2c4bbc8095e9a --- /dev/null +++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit @@ -0,0 +1,40 @@ +- // MIR for `exhaustive_match_i8` before MatchBranchSimplification ++ // MIR for `exhaustive_match_i8` after MatchBranchSimplification + + fn exhaustive_match_i8(_1: E) -> i8 { + debug e => _1; // in scope 0 at $DIR/matches_u8.rs:19:28: 19:29 + let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:19:37: 19:39 + let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:21:9: 21:13 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:21:9: 21:13 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:21:9: 21:13 + } + + bb1: { + _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18 + // ty::Const + // + ty: i8 + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/matches_u8.rs:22:17: 22:18 + // + literal: Const { ty: i8, val: Value(Scalar(0x01)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6 + } + + bb2: { + _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18 + // ty::Const + // + ty: i8 + // + val: Value(Scalar(0x00)) + // mir::Constant + // + span: $DIR/matches_u8.rs:21:17: 21:18 + // + literal: Const { ty: i8, val: Value(Scalar(0x00)) } + goto -> bb3; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6 + } + + bb3: { + return; // scope 0 at $DIR/matches_u8.rs:24:2: 24:2 + } + } + diff --git a/src/test/mir-opt/matches_u8.rs b/src/test/mir-opt/matches_u8.rs new file mode 100644 index 0000000000000..78373be48b685 --- /dev/null +++ b/src/test/mir-opt/matches_u8.rs @@ -0,0 +1,32 @@ +// EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff +// EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff + +pub enum E { + A, + B, +} + +#[no_mangle] +pub fn exhaustive_match(e: E) -> u8 { + match e { + E::A => 0, + E::B => 1, + } +} + +#[no_mangle] +pub fn exhaustive_match_i8(e: E) -> i8 { + match e { + E::A => 0, + E::B => 1, + } +} + +fn main() { + assert_eq!(exhaustive_match(E::A), 0); + assert_eq!(exhaustive_match(E::B), 1); + + assert_eq!(exhaustive_match_i8(E::A), 0); + assert_eq!(exhaustive_match_i8(E::B), 1); +}