diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs index da101ca7ad279..dbf5c599ff981 100644 --- a/compiler/rustc_mir_transform/src/const_goto.rs +++ b/compiler/rustc_mir_transform/src/const_goto.rs @@ -28,7 +28,7 @@ pub struct ConstGoto; impl<'tcx> MirPass<'tcx> for ConstGoto { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 4 + sess.mir_opt_level() >= 1 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index b2c477c84d2ff..67fc14746cb29 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -94,6 +94,7 @@ mod ssa; pub mod simplify; mod simplify_branches; mod simplify_comparison_integral; +mod sink_const_assignments; mod sroa; mod uninhabited_enum_branching; mod unreachable_prop; @@ -574,6 +575,8 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, &dead_store_elimination::DeadStoreElimination, + &sink_const_assignments::SinkConstAssignments, + &const_goto::ConstGoto, &dest_prop::DestinationPropagation, &o1(simplify_branches::SimplifyConstCondition::new("final")), &o1(remove_noop_landing_pads::RemoveNoopLandingPads), diff --git a/compiler/rustc_mir_transform/src/sink_const_assignments.rs b/compiler/rustc_mir_transform/src/sink_const_assignments.rs new file mode 100644 index 0000000000000..60ee73ab55f6e --- /dev/null +++ b/compiler/rustc_mir_transform/src/sink_const_assignments.rs @@ -0,0 +1,222 @@ +use crate::MirPass; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +const SUCCESSOR_LIMIT: usize = 100; + +pub struct SinkConstAssignments; + +impl<'tcx> MirPass<'tcx> for SinkConstAssignments { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 1 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // The primary benefit of this pass is sinking assignments to drop flags and enabling + // ConstGoto and SimplifyCfg to merge the drop flag check into existing control flow. + // If we permit sinking assignments to any local, we will sometimes sink an assignment into + // but not completely through a goto chain, preventing SimplifyCfg from removing the + // blocks. + let mut optimizable_locals = branched_locals(body); + if optimizable_locals.is_empty() { + return; + } + + let borrowed_locals = rustc_mir_dataflow::impls::borrowed_locals(body); + optimizable_locals.subtract(&borrowed_locals); + if optimizable_locals.is_empty() { + return; + } + + 'outer: for block in 0..body.basic_blocks.len() { + let block = block.into(); + let block_data = &body.basic_blocks[block]; + let Some(terminator) = &block_data.terminator else { continue; }; + + let mut successors = Vec::new(); + for succ in terminator.successors() { + // Successors which are just a Resume are okay + if is_empty_resume(&body.basic_blocks[succ]) { + continue; + } + if body.basic_blocks.predecessors()[succ].len() != 1 { + debug!("Bailing from {block:?} because {succ:?} has multiple predecessors"); + continue 'outer; + } + successors.push(succ); + } + + if successors.len() > SUCCESSOR_LIMIT { + debug!("Will not sink assignment, its basic block has too many successors"); + } + + let mut local_uses = None; + for statement_idx in 0..body.basic_blocks[block].statements.len() { + let statement = &body.basic_blocks[block].statements[statement_idx]; + if let StatementKind::Assign(box (place, Rvalue::Use(Operand::Constant(_)))) = + &statement.kind + { + let local = place.local; + if !place.projection.is_empty() { + debug!("Nonempty place projection: {statement:?}"); + continue; + } + if !optimizable_locals.contains(local) { + continue; + } + + let uses = match &local_uses { + Some(uses) => uses, + None => { + let mut visitor = CountUsesVisitor::new(); + visitor.visit_basic_block_data(block, &body.basic_blocks[block]); + local_uses = Some(visitor); + local_uses.as_ref().unwrap() + } + }; + + // If the local dies in this block, don't propagate it + if uses.dead.contains(&local) { + continue; + } + if !uses.is_used_once(local) { + debug!("Local used elsewhere in this block: {statement:?}"); + continue; + } + if !tcx.consider_optimizing(|| format!("Sinking const assignment to {local:?}")) + { + debug!("optimization fuel exhausted"); + break 'outer; + } + debug!("Sinking const assignment to {local:?}"); + let blocks = body.basic_blocks.as_mut_preserves_cfg(); + let statement = blocks[block].statements[statement_idx].replace_nop(); + + for succ in &successors { + let mut successor_uses = SuccessorUsesVisitor::new(local); + successor_uses.visit_basic_block_data(*succ, &blocks[*succ]); + + if let Some(used) = successor_uses.first_use() { + if used == blocks[*succ].statements.len() { + blocks[*succ].statements.push(statement.clone()); + continue; + } + // If the first use of our local in this block is another const + // assignment to it, do not paste a new assignment right before it + // because that would just create dead code. + if let StatementKind::Assign(box ( + place, + Rvalue::Use(Operand::Constant(_)), + )) = &blocks[*succ].statements[used].kind + { + if place.local == local && place.projection.is_empty() { + continue; + } + } + blocks[*succ].statements.insert(used, statement.clone()); + } else { + blocks[*succ].statements.push(statement.clone()); + } + } + } + } + } + } +} + +fn branched_locals(body: &Body<'_>) -> BitSet { + let mut visitor = BranchedLocals { + branched: BitSet::new_empty(body.local_decls.len()), + gets_const_assign: BitSet::new_empty(body.local_decls.len()), + }; + visitor.visit_body(body); + visitor.branched.intersect(&visitor.gets_const_assign); + visitor.branched +} + +struct BranchedLocals { + branched: BitSet, + gets_const_assign: BitSet, +} + +impl Visitor<'_> for BranchedLocals { + fn visit_terminator(&mut self, terminator: &Terminator<'_>, _location: Location) { + let TerminatorKind::SwitchInt { discr, .. } = &terminator.kind else { return; }; + if let Some(place) = discr.place() { + self.branched.insert(place.local); + } + } + + fn visit_statement(&mut self, statement: &Statement<'_>, _location: Location) { + if let StatementKind::Assign(box (place, Rvalue::Use(Operand::Constant(_)))) = + &statement.kind + { + if place.projection.is_empty() { + self.gets_const_assign.insert(place.local); + } + } + } +} + +fn is_empty_resume<'tcx>(block: &BasicBlockData<'tcx>) -> bool { + block.statements.iter().all(|s| matches!(s.kind, StatementKind::Nop)) + && block.terminator.as_ref().map(|t| &t.kind) == Some(&TerminatorKind::Resume) +} + +struct CountUsesVisitor { + counts: FxHashMap, + dead: FxHashSet, +} + +impl CountUsesVisitor { + fn new() -> Self { + Self { counts: FxHashMap::default(), dead: FxHashSet::default() } + } + + fn is_used_once(&self, local: Local) -> bool { + self.counts.get(&local) == Some(&1) + } +} + +impl Visitor<'_> for CountUsesVisitor { + fn visit_local(&mut self, local: Local, context: PlaceContext, _location: Location) { + match context { + PlaceContext::NonUse(NonUseContext::StorageDead) => { + self.dead.insert(local); + } + PlaceContext::NonUse(_) => {} + PlaceContext::MutatingUse(_) | PlaceContext::NonMutatingUse(_) => { + *self.counts.entry(local).or_default() += 1; + } + }; + } +} + +struct SuccessorUsesVisitor { + local: Local, + first_use: Option, +} + +impl SuccessorUsesVisitor { + fn new(local: Local) -> Self { + Self { local, first_use: None } + } + + fn first_use(&self) -> Option { + self.first_use + } +} + +impl Visitor<'_> for SuccessorUsesVisitor { + fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) { + if local == self.local { + match self.first_use { + None => self.first_use = Some(location.statement_index), + Some(first) => self.first_use = Some(first.min(location.statement_index)), + } + } + } +} diff --git a/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff b/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff index a717d1bbd12f2..52c9a4bfcc1f5 100644 --- a/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff +++ b/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff @@ -4,48 +4,24 @@ fn issue_77355_opt(_1: Foo) -> u64 { debug num => _1; // in scope 0 at $DIR/const_goto.rs:+0:20: +0:23 let mut _0: u64; // return place in scope 0 at $DIR/const_goto.rs:+0:33: +0:36 -- 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/const_goto.rs:+1:22: +1:28 -+ let mut _2: isize; // in scope 0 at $DIR/const_goto.rs:+1:22: +1:28 + let mut _2: isize; // in scope 0 at $DIR/const_goto.rs:+1:22: +1:28 bb0: { -- StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- _3 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:+1:17: +1:20 -- switchInt(move _3) -> [1: bb2, 2: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _2 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:+1:17: +1:20 -+ switchInt(move _2) -> [1: bb2, 2: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _2 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:+1:17: +1:20 + switchInt(move _2) -> [1: bb2, 2: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb1: { -- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:+1:53: +1:55 -+ goto -> bb3; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 + _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:+1:53: +1:55 + goto -> bb3; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 } bb2: { -- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb3: { -- switchInt(move _2) -> [0: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb4: { _0 = const 23_u64; // scope 0 at $DIR/const_goto.rs:+1:41: +1:43 -- goto -> bb6; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 -+ goto -> bb3; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 + goto -> bb3; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 } -- bb5: { -- _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:+1:53: +1:55 -- goto -> bb6; // scope 0 at $DIR/const_goto.rs:+1:5: +1:57 -- } -- -- bb6: { -- StorageDead(_2); // scope 0 at $DIR/const_goto.rs:+1:56: +1:57 -+ bb3: { + bb3: { return; // scope 0 at $DIR/const_goto.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff b/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff index 24be8c9b86845..bcc1824598bc2 100644 --- a/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff +++ b/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff @@ -14,35 +14,25 @@ } bb1: { - _1 = const true; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+4:18: +4:22 goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+4:18: +4:22 } bb2: { _1 = const B; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+3:26: +3:27 -- goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+3:26: +3:27 -+ switchInt(_1) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6 + switchInt(_1) -> [0: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6 } bb3: { -- switchInt(_1) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+1:5: +6:6 -- } -- -- bb4: { _0 = const 2_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 -- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 -+ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 + goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+8:17: +8:18 } -- bb5: { -+ bb4: { + bb4: { _0 = const 1_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 -- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 -+ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 + goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+7:18: +7:19 } -- bb6: { -+ bb5: { + bb5: { StorageDead(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:+10:1: +10:2 StorageDead(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:+10:1: +10:2 return; // scope 0 at $DIR/const_goto_const_eval_fail.rs:+10:2: +10:2 diff --git a/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff b/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff index 4dc98f8567402..5169eb38256e6 100644 --- a/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff +++ b/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff @@ -4,97 +4,31 @@ fn match_nested_if() -> bool { let mut _0: bool; // return place in scope 0 at $DIR/const_goto_storage.rs:+0:25: +0:29 let _1: bool; // in scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12 -- let mut _2: (); // in scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- let mut _3: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- let mut _4: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- let mut _5: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- let mut _6: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ let mut _2: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 + let mut _2: bool; // in scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 scope 1 { debug val => _1; // in scope 1 at $DIR/const_goto_storage.rs:+1:9: +1:12 } bb0: { StorageLive(_1); // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12 -- StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- _2 = (); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- StorageLive(_3); // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- StorageLive(_4); // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- StorageLive(_5); // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- StorageLive(_6); // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -- _6 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -- switchInt(move _6) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ _2 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 -+ switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 + StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 + _2 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 + switchInt(move _2) -> [0: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_storage.rs:+2:24: +2:28 } bb1: { -- _5 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:31: +2:35 -- goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- } -- -- bb2: { -- _5 = const false; // scope 0 at $DIR/const_goto_storage.rs:+2:45: +2:50 -- goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- } -- -- bb3: { -- StorageDead(_6); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 -- switchInt(move _5) -> [0: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 -- } -- -- bb4: { -- _4 = const true; // scope 0 at $DIR/const_goto_storage.rs:+2:55: +2:59 -- goto -> bb6; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- } -- -- bb5: { -- _4 = const false; // scope 0 at $DIR/const_goto_storage.rs:+2:69: +2:74 -- goto -> bb6; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- } -- -- bb6: { -- StorageDead(_5); // scope 0 at $DIR/const_goto_storage.rs:+2:75: +2:76 -- switchInt(move _4) -> [0: bb8, otherwise: bb7]; // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 -- } -- -- bb7: { -- _3 = const true; // scope 0 at $DIR/const_goto_storage.rs:+3:13: +3:17 -- goto -> bb9; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- } -- -- bb8: { -- _3 = const false; // scope 0 at $DIR/const_goto_storage.rs:+5:13: +5:18 -- goto -> bb9; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- } -- -- bb9: { -- switchInt(move _3) -> [0: bb11, otherwise: bb10]; // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 -- } -- -- bb10: { -- StorageDead(_4); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -- StorageDead(_3); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -+ StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 + StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 _1 = const true; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 -- goto -> bb12; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 -+ goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 + goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+8:17: +8:21 } -- bb11: { -- StorageDead(_4); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -- StorageDead(_3); // scope 0 at $DIR/const_goto_storage.rs:+6:9: +6:10 -+ bb2: { -+ StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 + bb2: { + StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+2:51: +2:52 _1 = const false; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 -- goto -> bb12; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 -+ goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 + goto -> bb3; // scope 0 at $DIR/const_goto_storage.rs:+10:14: +10:19 } -- bb12: { -- StorageDead(_2); // scope 0 at $DIR/const_goto_storage.rs:+11:6: +11:7 -+ bb3: { + bb3: { _0 = _1; // scope 1 at $DIR/const_goto_storage.rs:+12:5: +12:8 StorageDead(_1); // scope 0 at $DIR/const_goto_storage.rs:+13:1: +13:2 return; // scope 0 at $DIR/const_goto_storage.rs:+13:2: +13:2 diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index 6e28fb61b6bd7..5dfe6a3a027d6 100644 --- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -28,41 +28,44 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23 StorageLive(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageLive(_5); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _5 = char::methods::::to_digit(_1, const 8_u32) -> bb5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + _5 = char::methods::::to_digit(_1, const 8_u32) -> bb3; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/char/methods.rs:LL:COL // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } } bb1: { - StorageLive(_2); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 - _2 = char::methods::::to_digit(_1, const 8_u32) -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 - // mir::Constant - // + span: $DIR/issue_59352.rs:14:30: 14:38 - // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } + _7 = discriminant(_2); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _7) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } bb2: { - _7 = discriminant(_2); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - switchInt(move _7) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2 } bb3: { - _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61 - goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + _4 = &_5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + _6 = discriminant((*_4)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _6) -> [1: bb5, otherwise: bb4]; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb4: { - return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2 + StorageDead(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + StorageDead(_5); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL + StorageDead(_3); // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23 + _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61 + goto -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 } bb5: { - _4 = &_5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _6 = discriminant((*_4)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL StorageDead(_4); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageDead(_5); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL StorageDead(_3); // scope 0 at $DIR/issue_59352.rs:+2:12: +2:23 - switchInt(move _6) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 + StorageLive(_2); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + _2 = char::methods::::to_digit(_1, const 8_u32) -> bb1; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 + // mir::Constant + // + span: $DIR/issue_59352.rs:14:30: 14:38 + // + literal: Const { ty: fn(char, u32) -> Option {char::methods::::to_digit}, val: Value() } } bb6: { @@ -82,6 +85,6 @@ fn num_to_digit(_1: char) -> u32 { bb8: { _0 = move ((_2 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL StorageDead(_2); // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50 - goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 + goto -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63 } } diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir new file mode 100644 index 0000000000000..0440cfce2893f --- /dev/null +++ b/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir @@ -0,0 +1,58 @@ +// MIR for `array_bound_mut` after PreCodegen + +fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + let mut _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let mut _7: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 + switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + } + + bb1: { + _6 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + _7 = Lt(_1, _6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + } + + bb2: { + _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + _8 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + _9 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + _10 = Lt(const 0_usize, _9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + } + + bb4: { + (*_2)[_8] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22 + StorageDead(_8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6 + return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2 + } +} diff --git a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir index cae89fb177a7c..df9655f1dd555 100644 --- a/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir +++ b/tests/mir-opt/simple_option_map_e2e.ezmap.PreCodegen.after.mir @@ -24,7 +24,7 @@ fn ezmap(_1: Option) -> Option { bb1: { _0 = Option::::None; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21 - return; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21 + return; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2 } bb2: { @@ -37,6 +37,6 @@ fn ezmap(_1: Option) -> Option { _4 = Add(_3, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 _0 = Option::::Some(move _4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 StorageDead(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30 - return; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2 + return; // scope 0 at $DIR/simple_option_map_e2e.rs:10:1: 10:2 } }