diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 9a6b6532ce88f..ac88060f0d349 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -1,12 +1,12 @@ use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use std::fmt::Debug; use super::simplify::simplify_cfg; /// This pass optimizes something like -/// ```ignore (syntax-highlighting-only) +/// ```text /// let x: Option<()>; /// let y: Option<()>; /// match (x,y) { @@ -15,201 +15,144 @@ use super::simplify::simplify_cfg; /// } /// ``` /// into something like -/// ```ignore (syntax-highlighting-only) +/// ```text /// let x: Option<()>; /// let y: Option<()>; -/// let discriminant_x = std::mem::discriminant(x); -/// let discriminant_y = std::mem::discriminant(y); -/// if discriminant_x == discriminant_y { -/// match x { -/// Some(_) => 0, -/// _ => 1, // <---- -/// } // | Actually the same bb -/// } else { // | -/// 1 // <-------------- -/// } -/// ``` -/// -/// Specifically, it looks for instances of control flow like this: -/// ```text -/// -/// ================= -/// | BB1 | -/// |---------------| ============================ -/// | ... | /------> | BBC | -/// |---------------| | |--------------------------| -/// | switchInt(Q) | | | _cl = discriminant(P) | -/// | c | --------/ |--------------------------| -/// | d | -------\ | switchInt(_cl) | -/// | ... | | | c | ---> BBC.2 -/// | otherwise | --\ | /--- | otherwise | -/// ================= | | | ============================ -/// | | | -/// ================= | | | -/// | BBU | <-| | | ============================ -/// |---------------| | \-------> | BBD | -/// |---------------| | | |--------------------------| -/// | unreachable | | | | _dl = discriminant(P) | -/// ================= | | |--------------------------| -/// | | | switchInt(_dl) | -/// ================= | | | d | ---> BBD.2 -/// | BB9 | <--------------- | otherwise | -/// |---------------| ============================ -/// | ... | -/// ================= +/// let discriminant_x = // get discriminant of x +/// let discriminant_y = // get discriminant of y +/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0} /// ``` -/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the -/// code: -/// - `BB1` is `parent` and `BBC, BBD` are children -/// - `P` is `child_place` -/// - `child_ty` is the type of `_cl`. -/// - `Q` is `parent_op`. -/// - `parent_ty` is the type of `Q`. -/// - `BB9` is `destination` -/// All this is then transformed into: -/// ```text -/// -/// ======================= -/// | BB1 | -/// |---------------------| ============================ -/// | ... | /------> | BBEq | -/// | _s = discriminant(P)| | |--------------------------| -/// | _t = Ne(Q, _s) | | |--------------------------| -/// |---------------------| | | switchInt(Q) | -/// | switchInt(_t) | | | c | ---> BBC.2 -/// | false | --------/ | d | ---> BBD.2 -/// | otherwise | ---------------- | otherwise | -/// ======================= | ============================ -/// | -/// ================= | -/// | BB9 | <-----------/ -/// |---------------| -/// | ... | -/// ================= -/// ``` -/// -/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`. -/// The filter on which `P` are allowed (together with discussion of its correctness) is found in -/// `may_hoist`. pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 2 + // FIXME(#78496) + sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { trace!("running EarlyOtherwiseBranch on {:?}", body.source); - let mut should_cleanup = false; + // we are only interested in this bb if the terminator is a switchInt + let bbs_with_switch = + body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator())); - // Also consider newly generated bbs in the same pass - for i in 0..body.basic_blocks().len() { - let bbs = body.basic_blocks(); - let parent = BasicBlock::from_usize(i); - let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { - continue - }; + let opts_to_apply: Vec> = bbs_with_switch + .flat_map(|(bb_idx, bb)| { + let switch = bb.terminator(); + let helper = Helper { body, tcx }; + let infos = helper.go(bb, switch)?; + Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx }) + }) + .collect(); + + let should_cleanup = !opts_to_apply.is_empty(); - if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_data)) { + for opt_to_apply in opts_to_apply { + if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) { break; } - trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_data); + trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply); - should_cleanup = true; - - let TerminatorKind::SwitchInt { - discr: parent_op, - switch_ty: parent_ty, - targets: parent_targets - } = &bbs[parent].terminator().kind else { - unreachable!() - }; - // Always correct since we can only switch on `Copy` types - let parent_op = match parent_op { - Operand::Move(x) => Operand::Copy(*x), - Operand::Copy(x) => Operand::Copy(*x), - Operand::Constant(x) => Operand::Constant(x.clone()), + let statements_before = + body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len(); + let end_of_block_location = Location { + block: opt_to_apply.basic_block_first_switch, + statement_index: statements_before, }; - let statements_before = bbs[parent].statements.len(); - let parent_end = Location { block: parent, statement_index: statements_before }; let mut patch = MirPatch::new(body); - // create temp to store second discriminant in, `_s` in example above - let second_discriminant_temp = - patch.new_temp(opt_data.child_ty, opt_data.child_source.span); + // create temp to store second discriminant in + let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty; + let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span; + let second_discriminant_temp = patch.new_temp(discr_type, discr_span); - patch.add_statement(parent_end, StatementKind::StorageLive(second_discriminant_temp)); + patch.add_statement( + end_of_block_location, + StatementKind::StorageLive(second_discriminant_temp), + ); // create assignment of discriminant + let place_of_adt_to_get_discriminant_of = + opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read; patch.add_assign( - parent_end, + end_of_block_location, Place::from(second_discriminant_temp), - Rvalue::Discriminant(opt_data.child_place), + Rvalue::Discriminant(place_of_adt_to_get_discriminant_of), ); - // create temp to store inequality comparison between the two discriminants, `_t` in - // example above - let nequal = BinOp::Ne; - let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty); - let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span); - patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp)); - - // create inequality comparison between the two discriminants - let comp_rvalue = Rvalue::BinaryOp( - nequal, - Box::new((parent_op.clone(), Operand::Move(Place::from(second_discriminant_temp)))), + // create temp to store NotEqual comparison between the two discriminants + let not_equal = BinOp::Ne; + let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type); + let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span); + patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp)); + + // create NotEqual comparison between the two discriminants + let first_descriminant_place = + opt_to_apply.infos[0].first_switch_info.discr_used_in_switch; + let not_equal_rvalue = Rvalue::BinaryOp( + not_equal, + Box::new(( + Operand::Copy(Place::from(second_discriminant_temp)), + Operand::Copy(first_descriminant_place), + )), ); patch.add_statement( - parent_end, - StatementKind::Assign(Box::new((Place::from(comp_temp), comp_rvalue))), + end_of_block_location, + StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))), ); - let eq_new_targets = parent_targets.iter().map(|(value, child)| { - let TerminatorKind::SwitchInt{ targets, .. } = &bbs[child].terminator().kind else { - unreachable!() - }; - (value, targets.target_for_value(value)) - }); - let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination); - - // Create `bbEq` in example above - let eq_switch = BasicBlockData::new(Some(Terminator { - source_info: bbs[parent].terminator().source_info, + let new_targets = opt_to_apply + .infos + .iter() + .flat_map(|x| x.second_switch_info.targets_with_values.iter()) + .cloned(); + + let targets = SwitchTargets::new( + new_targets, + opt_to_apply.infos[0].first_switch_info.otherwise_bb, + ); + + // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal + let new_switch_data = BasicBlockData::new(Some(Terminator { + source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, kind: TerminatorKind::SwitchInt { - // switch on the first discriminant, so we can mark the second one as dead - discr: parent_op, - switch_ty: opt_data.child_ty, - targets: eq_targets, + // the first and second discriminants are equal, so just pick one + discr: Operand::Copy(first_descriminant_place), + switch_ty: discr_type, + targets, }, })); - let eq_bb = patch.new_block(eq_switch); + let new_switch_bb = patch.new_block(new_switch_data); - // Jump to it on the basis of the inequality comparison - let true_case = opt_data.destination; - let false_case = eq_bb; + // switch on the NotEqual. If true, then jump to the `otherwise` case. + // If false, then jump to a basic block that then jumps to the correct disciminant case + let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb; + let false_case = new_switch_bb; patch.patch_terminator( - parent, + opt_to_apply.basic_block_first_switch, TerminatorKind::if_( tcx, - Operand::Move(Place::from(comp_temp)), + Operand::Move(Place::from(not_equal_temp)), true_case, false_case, ), ); // generate StorageDead for the second_discriminant_temp not in use anymore - patch.add_statement(parent_end, StatementKind::StorageDead(second_discriminant_temp)); + patch.add_statement( + end_of_block_location, + StatementKind::StorageDead(second_discriminant_temp), + ); - // Generate a StorageDead for comp_temp in each of the targets, since we moved it into - // the switch + // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch for bb in [false_case, true_case].iter() { patch.add_statement( Location { block: *bb, statement_index: 0 }, - StatementKind::StorageDead(comp_temp), + StatementKind::StorageDead(not_equal_temp), ); } @@ -224,177 +167,201 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { } } -/// Returns true if computing the discriminant of `place` may be hoisted out of the branch -fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool { - for (place, proj) in place.iter_projections() { - match proj { - // Dereferencing in the computation of `place` might cause issues from one of two - // cateogires. First, the referrent might be invalid. We protect against this by - // dereferencing references only (not pointers). Second, the use of a reference may - // invalidate other references that are used later (for aliasing reasons). Consider - // where such an invalidated reference may appear: - // - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so - // cannot contain referenced data. - // - In `BBU`: Not possible since that block contains only the `unreachable` terminator - // - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to - // reaching that block in the input to our transformation, and so any data - // invalidated by that computation could not have been used there. - // - In `BB9`: Not possible since control flow might have reached `BB9` via the - // `otherwise` branch in `BBC, BBD` in the input to our transformation, which would - // have invalidated the data when computing `discriminant(P)` - // So dereferencing here is correct. - ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() { - ty::Ref(..) => {} - _ => return false, - }, - // Field projections are always valid - ProjectionElem::Field(..) => {} - // We cannot allow - // downcasts either, since the correctness of the downcast may depend on the parent - // branch being taken. An easy example of this is - // ``` - // Q = discriminant(_3) - // P = (_3 as Variant) - // ``` - // However, checking if the child and parent place are the same and only erroring then - // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may - // be replaced by another optimization pass with any other condition that can be proven - // equivalent. - ProjectionElem::Downcast(..) => { - return false; - } - // We cannot allow indexing since the index may be out of bounds. - _ => { - return false; - } - } - } - true +fn is_switch(terminator: &Terminator<'_>) -> bool { + matches!(terminator.kind, TerminatorKind::SwitchInt { .. }) +} + +struct Helper<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, +} + +#[derive(Debug, Clone)] +struct SwitchDiscriminantInfo<'tcx> { + /// Type of the discriminant being switched on + discr_ty: Ty<'tcx>, + /// The basic block that the otherwise branch points to + otherwise_bb: BasicBlock, + /// Target along with the value being branched from. Otherwise is not included + targets_with_values: Vec<(u128, BasicBlock)>, + discr_source_info: SourceInfo, + /// The place of the discriminant used in the switch + discr_used_in_switch: Place<'tcx>, + /// The place of the adt that has its discriminant read + place_of_adt_discr_read: Place<'tcx>, + /// The type of the adt that has its discriminant read + type_adt_matched_on: Ty<'tcx>, } #[derive(Debug)] -struct OptimizationData<'tcx> { - destination: BasicBlock, - child_place: Place<'tcx>, - child_ty: Ty<'tcx>, - child_source: SourceInfo, +struct OptimizationToApply<'tcx> { + infos: Vec>, + /// Basic block of the original first switch + basic_block_first_switch: BasicBlock, } -fn evaluate_candidate<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - parent: BasicBlock, -) -> Option> { - let bbs = body.basic_blocks(); - let TerminatorKind::SwitchInt { - targets, - switch_ty: parent_ty, - .. - } = &bbs[parent].terminator().kind else { - return None - }; - let parent_dest = { - let poss = targets.otherwise(); - // If the fallthrough on the parent is trivially unreachable, we can let the - // children choose the destination - if bbs[poss].statements.len() == 0 - && bbs[poss].terminator().kind == TerminatorKind::Unreachable - { - None - } else { - Some(poss) - } - }; - let Some((_, child)) = targets.iter().next() else { - return None - }; - let child_terminator = &bbs[child].terminator(); - let TerminatorKind::SwitchInt { - switch_ty: child_ty, - targets: child_targets, - .. - } = &child_terminator.kind else { - return None - }; - if child_ty != parent_ty { - return None; - } - let Some(StatementKind::Assign(boxed)) - = &bbs[child].statements.first().map(|x| &x.kind) else { - return None; - }; - let (_, Rvalue::Discriminant(child_place)) = &**boxed else { - return None; - }; - let destination = parent_dest.unwrap_or(child_targets.otherwise()); - - // Verify that the optimization is legal in general - // We can hoist evaluating the child discriminant out of the branch - if !may_hoist(tcx, body, *child_place) { - return None; - } +#[derive(Debug)] +struct OptimizationInfo<'tcx> { + /// Info about the first switch and discriminant + first_switch_info: SwitchDiscriminantInfo<'tcx>, + /// Info about the second switch and discriminant + second_switch_info: SwitchDiscriminantInfo<'tcx>, +} + +impl<'tcx> Helper<'_, 'tcx> { + pub fn go( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option>> { + // try to find the statement that defines the discriminant that is used for the switch + let discr = self.find_switch_discriminant_info(bb, switch)?; - // Verify that the optimization is legal for each branch - for (value, child) in targets.iter() { - if !verify_candidate_branch(&bbs[child], value, *child_place, destination) { + // go through each target, finding a discriminant read, and a switch + let results = discr + .targets_with_values + .iter() + .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value)); + + // if the optimization did not apply for one of the targets, then abort + if results.clone().any(|x| x.is_none()) || results.len() == 0 { + trace!("NO: not all of the targets matched the pattern for optimization"); return None; } - } - Some(OptimizationData { - destination, - child_place: *child_place, - child_ty, - child_source: child_terminator.source_info, - }) -} -fn verify_candidate_branch<'tcx>( - branch: &BasicBlockData<'tcx>, - value: u128, - place: Place<'tcx>, - destination: BasicBlock, -) -> bool { - // In order for the optimization to be correct, the branch must... - // ...have exactly one statement - if branch.statements.len() != 1 { - return false; - } - // ...assign the descriminant of `place` in that statement - let StatementKind::Assign(boxed) = &branch.statements[0].kind else { - return false - }; - let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { - return false - }; - if *from_place != place { - return false; - } - // ...make that assignment to a local - if discr_place.projection.len() != 0 { - return false; - } - // ...terminate on a `SwitchInt` that invalidates that local - let TerminatorKind::SwitchInt{ discr: switch_op, targets, .. } = &branch.terminator().kind else { - return false - }; - if *switch_op != Operand::Move(*discr_place) { - return false; + Some(results.flatten().collect()) } - // ...fall through to `destination` if the switch misses - if destination != targets.otherwise() { - return false; - } - // ...have a branch for value `value` - let mut iter = targets.iter(); - let Some((target_value, _)) = iter.next() else { - return false; - }; - if target_value != value { - return false; + + fn find_discriminant_switch_pairing( + &self, + discr_info: &SwitchDiscriminantInfo<'tcx>, + target: BasicBlock, + value: u128, + ) -> Option> { + let bb = &self.body.basic_blocks()[target]; + // find switch + let terminator = bb.terminator(); + if is_switch(terminator) { + let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?; + + // the types of the two adts matched on have to be equalfor this optimization to apply + if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on { + trace!( + "NO: types do not match. LHS: {:?}, RHS: {:?}", + discr_info.type_adt_matched_on, + this_bb_discr_info.type_adt_matched_on + ); + return None; + } + + // the otherwise branch of the two switches have to point to the same bb + if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb { + trace!("NO: otherwise target is not the same"); + return None; + } + + // check that the value being matched on is the same. The + if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) { + trace!("NO: values being matched on are not the same"); + return None; + } + + // only allow optimization if the left and right of the tuple being matched are the same variants. + // so the following should not optimize + // ```rust + // let x: Option<()>; + // let y: Option<()>; + // match (x,y) { + // (Some(_), None) => {}, + // _ => {} + // } + // ``` + // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch + if !(this_bb_discr_info.targets_with_values.len() == 1 + && this_bb_discr_info.targets_with_values[0].0 == value) + { + trace!( + "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" + ); + return None; + } + + // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. + // for example, this should not be optimized: + // + // ```rust + // enum E<'a> { Empty, Some(&'a E<'a>), } + // let Some(Some(_)) = e; + // ``` + // + // ```mir + // bb0: { + // _2 = discriminant(*_1) + // switchInt(_2) -> [...] + // } + // bb1: { + // _3 = discriminant(*(((*_1) as Some).0: &E)) + // switchInt(_3) -> [...] + // } + // ``` + let discr_place = discr_info.place_of_adt_discr_read; + let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; + if discr_place.local == this_discr_place.local + && this_discr_place.projection.starts_with(discr_place.projection) + { + trace!("NO: one target is the projection of another"); + return None; + } + + // if we reach this point, the optimization applies, and we should be able to optimize this case + // store the info that is needed to apply the optimization + + Some(OptimizationInfo { + first_switch_info: discr_info.clone(), + second_switch_info: this_bb_discr_info, + }) + } else { + None + } } - // ...and have no more branches - if let Some(_) = iter.next() { - return false; + + fn find_switch_discriminant_info( + &self, + bb: &BasicBlockData<'tcx>, + switch: &Terminator<'tcx>, + ) -> Option> { + match &switch.kind { + TerminatorKind::SwitchInt { discr, targets, .. } => { + let discr_local = discr.place()?.as_local()?; + // the declaration of the discriminant read. Place of this read is being used in the switch + let discr_decl = &self.body.local_decls()[discr_local]; + let discr_ty = discr_decl.ty; + // the otherwise target lies as the last element + let otherwise_bb = targets.otherwise(); + let targets_with_values = targets.iter().collect(); + + // find the place of the adt where the discriminant is being read from + // assume this is the last statement of the block + let place_of_adt_discr_read = match bb.statements.last()?.kind { + StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => { + Some(adt_place) + } + _ => None, + }?; + + let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty; + + Some(SwitchDiscriminantInfo { + discr_used_in_switch: discr.place()?, + discr_ty, + otherwise_bb, + targets_with_values, + discr_source_info: discr_decl.source_info, + place_of_adt_discr_read, + type_adt_matched_on, + }) + } + _ => unreachable!("must only be passed terminator that is a switch"), + } } - return true; } diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 3fe23633852ed..c1591e5d72915 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -12,8 +12,8 @@ let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 scope 1 { debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16 debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25 @@ -34,7 +34,7 @@ + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 -+ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 + switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 } @@ -70,8 +70,8 @@ + } + + bb4: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 -+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 6d149b89edbb9..b949d307e20e9 100644 --- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -13,8 +13,8 @@ let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 -+ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 -+ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 scope 1 { debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16 debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25 @@ -35,7 +35,7 @@ + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 -+ _12 = Ne(_8, move _11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 + switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 } @@ -84,8 +84,8 @@ + } + + bb5: { -+ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 -+ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17 ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 } } diff --git a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff deleted file mode 100644 index 2aa22737bde2c..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `opt3` before EarlyOtherwiseBranch -+ // MIR for `opt3` after EarlyOtherwiseBranch - - fn opt3(_1: Option, _2: Option) -> u32 { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:21:9: 21:10 - debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:21:25: 21:26 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:21:45: 21:48 - let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 - let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 - let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 - let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:23:19: 23:26 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:23:10: 23:17 - let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 - let _9: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 -+ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 - scope 1 { - debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:23:15: 23:16 - debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:23:24: 23:25 - } - - bb0: { - StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 - _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 - _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16 - (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 - (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17 - _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 -- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ _11 = Ne(_7, move _10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 - } - - bb1: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 -- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 -+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15 - } - - bb2: { -- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17 -- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -- } -- -- bb3: { - StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 - _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16 - StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 - _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25 - _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:23:31: 23:32 - StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 - StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 -- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 -+ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32 - } - -- bb4: { -+ bb3: { - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2 - return; // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2 -+ } -+ -+ bb4: { -+ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 -+ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs index e0ebcfeebfcc7..b2caf7d7b8fde 100644 --- a/src/test/mir-opt/early_otherwise_branch.rs +++ b/src/test/mir-opt/early_otherwise_branch.rs @@ -16,17 +16,7 @@ fn opt2(x: Option, y: Option) -> u32 { } } -// optimize despite different types -// EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff -fn opt3(x: Option, y: Option) -> u32 { - match (x, y) { - (Some(a), Some(b)) => 0, - _ => 1, - } -} - fn main() { opt1(None, Some(0)); opt2(None, Some(0)); - opt3(None, Some(false)); } diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index 8b78f3ce20247..5b9ec1e53d946 100644 --- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -16,10 +16,10 @@ let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 -+ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 -+ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 -+ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 -+ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 scope 1 { debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 @@ -45,7 +45,7 @@ + StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 -+ _15 = Ne(_10, move _14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 + switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 } @@ -92,8 +92,8 @@ + } + + bb5: { -+ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 -+ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff index fc2dcb251099f..44294030439f3 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff @@ -36,8 +36,8 @@ let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28 let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 -+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 scope 1 { - debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 - debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 @@ -85,7 +85,7 @@ + StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ _35 = Ne(_11, move _34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } @@ -293,8 +293,8 @@ - StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7 - StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2 -+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 } } diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 28c650d72dc1d..af32d4d2d149c 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -36,8 +36,8 @@ let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28 let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27 -+ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 scope 1 { debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17 debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29 @@ -71,7 +71,7 @@ + StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ _35 = Ne(_11, move _34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 + switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 } @@ -209,8 +209,8 @@ + } + + bb7: { -+ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 -+ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30 } } diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000000..66ea828bf682c --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,60 @@ +- // MIR for `noopt2` before EarlyOtherwiseBranch ++ // MIR for `noopt2` after EarlyOtherwiseBranch + + fn noopt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:11: 18:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:27: 18:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:47: 18:50 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 19:17 + } + + bb1: { + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 19:17 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:1: 23:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:2: 23:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs index 1f8c59df35fff..d04e2a0429d5c 100644 --- a/src/test/mir-opt/early_otherwise_branch_noopt.rs +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -13,6 +13,16 @@ fn noopt1(x: Option, y: Option) -> u32 { } } +// must not optimize as the types being matched on are not identical +// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff +fn noopt2(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + _ => 1, + } +} + fn main() { noopt1(None, Some(0)); + noopt2(None, Some(true)); } diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff deleted file mode 100644 index a272266066246..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff +++ /dev/null @@ -1,43 +0,0 @@ -- // MIR for `no_deref_ptr` before EarlyOtherwiseBranch -+ // MIR for `no_deref_ptr` after EarlyOtherwiseBranch - - fn no_deref_ptr(_1: Option, _2: *const Option) -> i32 { - debug a => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:24: 18:25 - debug b => _2; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:40: 18:41 - let mut _0: i32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:66: 18:69 - let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:9: 21:16 - let mut _4: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:13: 22:20 - let _5: i32; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 - scope 1 { - debug v => _5; // in scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 - } - - bb0: { - _3 = discriminant(_1); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:11: 19:12 - switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:5: 19:12 - } - - bb1: { - _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15 - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15 - } - - bb2: { - _4 = discriminant((*_2)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:26: 21:28 - switchInt(move _4) -> [1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:20: 21:28 - } - - bb3: { - _0 = const 0_i32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19 - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19 - } - - bb4: { - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 - _5 = (((*_2) as Some).0: i32); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19 - _0 = _5; // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 - StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff deleted file mode 100644 index 56b7c9a2db478..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `no_downcast` before EarlyOtherwiseBranch -+ // MIR for `no_downcast` after EarlyOtherwiseBranch - - fn no_downcast(_1: &E) -> u32 { - debug e => _1; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17 - let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:26: 12:29 - let mut _2: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:20: 13:30 - let mut _3: isize; // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - - bb0: { - _3 = discriminant((*_1)); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - switchInt(move _3) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - } - - bb1: { - _2 = discriminant((*(((*_1) as Some).0: &E))); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31 - } - - bb2: { - _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39 - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52 - } - - bb3: { - _0 = const 2_u32; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50 - return; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.rs b/src/test/mir-opt/early_otherwise_branch_soundness.rs deleted file mode 100644 index d2513213d796f..0000000000000 --- a/src/test/mir-opt/early_otherwise_branch_soundness.rs +++ /dev/null @@ -1,32 +0,0 @@ -// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts - -// Tests various cases that the `early_otherwise_branch` opt should *not* optimize - -// From #78496 -enum E<'a> { - Empty, - Some(&'a E<'a>), -} - -// EMIT_MIR early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff -fn no_downcast(e: &E) -> u32 { - if let E::Some(E::Some(_)) = e { 1 } else { 2 } -} - -// SAFETY: if `a` is `Some`, `b` must point to a valid, initialized value -// EMIT_MIR early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff -unsafe fn no_deref_ptr(a: Option, b: *const Option) -> i32 { - match a { - // `*b` being correct depends on `a == Some(_)` - Some(_) => match *b { - Some(v) => v, - _ => 0, - }, - _ => 0, - } -} - -fn main() { - no_downcast(&E::Empty); - unsafe { no_deref_ptr(None, std::ptr::null()) }; -}