diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 3e45319431cec..2f1d3d765cb3b 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -207,13 +207,14 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { // This is the set of merges we will apply this round. It is a subset of the candidates. let mut merges = FxHashMap::default(); + let mut remove_writes = FxHashMap::default(); - for (src, candidates) in candidates.c.iter() { - if merged_locals.contains(*src) { + for (src, candidates) in candidates.c.drain() { + if merged_locals.contains(src) { continue; } let Some(dest) = - candidates.iter().find(|dest| !merged_locals.contains(**dest)) else { + candidates.into_iter().find(|(dest, _)| !merged_locals.contains(*dest)) else { continue; }; if !tcx.consider_optimizing(|| { @@ -221,9 +222,12 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { }) { break; } - merges.insert(*src, *dest); - merged_locals.insert(*src); - merged_locals.insert(*dest); + merged_locals.insert(src); + merged_locals.insert(dest.0); + merges.insert(src, dest.0); + if !dest.1.is_empty() { + remove_writes.insert(dest.0, dest.1); + } } trace!(merging = ?merges); @@ -232,7 +236,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { } round_count += 1; - apply_merges(body, tcx, &merges, &merged_locals); + apply_merges(body, tcx, &merges, &remove_writes, &merged_locals); } trace!(round_count); @@ -245,7 +249,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { /// frequently. Everything with a `&'alloc` lifetime points into here. #[derive(Default)] struct Allocations { - candidates: FxHashMap>, + candidates: FxHashMap)>>, candidates_reverse: FxHashMap>, write_info: WriteInfo, // PERF: Do this for `MaybeLiveLocals` allocations too. @@ -267,7 +271,11 @@ struct Candidates<'alloc> { /// /// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to /// remove that assignment. - c: &'alloc mut FxHashMap>, + /// + /// Each candidate pair is associated with a `Vec`. If the candidate pair is accepted, + /// all writes to either local at these locations must be removed. The writes will always be + /// removable. + c: &'alloc mut FxHashMap)>>, /// A reverse index of the `c` set; if the `c` set contains `a => Place { local: b, proj }`, /// then this contains `b => a`. // PERF: Possibly these should be `SmallVec`s? @@ -283,18 +291,29 @@ fn apply_merges<'tcx>( body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, merges: &FxHashMap, + remove_writes: &FxHashMap>, merged_locals: &BitSet, ) { - let mut merger = Merger { tcx, merges, merged_locals }; + let mut merger = Merger { tcx, merges, remove_writes, merged_locals }; merger.visit_body_preserves_cfg(body); } struct Merger<'a, 'tcx> { tcx: TyCtxt<'tcx>, merges: &'a FxHashMap, + remove_writes: &'a FxHashMap>, merged_locals: &'a BitSet, } +impl<'a, 'tcx> Merger<'a, 'tcx> { + fn should_remove_write_at(&self, local: Local, location: Location) -> bool { + let Some(to_remove) = self.remove_writes.get(&local) else { + return false; + }; + to_remove.contains(&location) + } +} + impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx @@ -332,10 +351,27 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> { _ => {} } } + StatementKind::Deinit(place) => { + if self.should_remove_write_at(place.local, location) { + statement.make_nop(); + } + } _ => {} } } + + fn visit_operand(&mut self, op: &mut Operand<'tcx>, location: Location) { + self.super_operand(op, location); + match op { + Operand::Move(place) => { + if self.should_remove_write_at(place.local, location) { + *op = Operand::Copy(*place); + } + } + _ => (), + } + } } ////////////////////////////////////////////////////////// @@ -356,30 +392,35 @@ struct FilterInformation<'a, 'body, 'alloc, 'tcx> { // through these methods, and not directly. impl<'alloc> Candidates<'alloc> { /// Just `Vec::retain`, but the condition is inverted and we add debugging output - fn vec_filter_candidates( + fn vec_modify_candidates( src: Local, - v: &mut Vec, - mut f: impl FnMut(Local) -> CandidateFilter, + v: &mut Vec<(Local, Vec)>, + mut f: impl FnMut(Local) -> CandidateModification, at: Location, ) { - v.retain(|dest| { - let remove = f(*dest); - if remove == CandidateFilter::Remove { + v.retain_mut(|(dest, remove_writes)| match f(*dest) { + CandidateModification::Remove => { trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at); + false + } + CandidateModification::RemoveWrite => { + trace!("marking write for {:?} => {:?} as needing removing at {:?}", src, dest, at); + remove_writes.push(at); + true } - remove == CandidateFilter::Keep + CandidateModification::Keep => true, }); } /// `vec_filter_candidates` but for an `Entry` fn entry_filter_candidates( - mut entry: OccupiedEntry<'_, Local, Vec>, + mut entry: OccupiedEntry<'_, Local, Vec<(Local, Vec)>>, p: Local, - f: impl FnMut(Local) -> CandidateFilter, + f: impl FnMut(Local) -> CandidateModification, at: Location, ) { let candidates = entry.get_mut(); - Self::vec_filter_candidates(p, candidates, f, at); + Self::vec_modify_candidates(p, candidates, f, at); if candidates.len() == 0 { entry.remove(); } @@ -389,7 +430,7 @@ impl<'alloc> Candidates<'alloc> { fn filter_candidates_by( &mut self, p: Local, - mut f: impl FnMut(Local) -> CandidateFilter, + mut f: impl FnMut(Local) -> CandidateModification, at: Location, ) { // Cover the cases where `p` appears as a `src` @@ -403,7 +444,8 @@ impl<'alloc> Candidates<'alloc> { // We use `retain` here to remove the elements from the reverse set if we've removed the // matching candidate in the forward set. srcs.retain(|src| { - if f(*src) == CandidateFilter::Keep { + let modification = f(*src); + if modification == CandidateModification::Keep { return true; } let Entry::Occupied(entry) = self.c.entry(*src) else { @@ -413,18 +455,20 @@ impl<'alloc> Candidates<'alloc> { entry, *src, |dest| { - if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep } + if dest == p { modification } else { CandidateModification::Keep } }, at, ); - false + // Remove the src from the reverse set if we removed the candidate pair + modification == CandidateModification::RemoveWrite }); } } #[derive(Copy, Clone, PartialEq, Eq)] -enum CandidateFilter { +enum CandidateModification { Keep, + RemoveWrite, Remove, } @@ -483,31 +527,36 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { fn apply_conflicts(&mut self) { let writes = &self.write_info.writes; - for p in writes { + for &(p, is_removable) in writes { + let modification = if is_removable { + CandidateModification::RemoveWrite + } else { + CandidateModification::Remove + }; let other_skip = self.write_info.skip_pair.and_then(|(a, b)| { - if a == *p { + if a == p { Some(b) - } else if b == *p { + } else if b == p { Some(a) } else { None } }); self.candidates.filter_candidates_by( - *p, + p, |q| { if Some(q) == other_skip { - return CandidateFilter::Keep; + return CandidateModification::Keep; } // It is possible that a local may be live for less than the // duration of a statement This happens in the case of function // calls or inline asm. Because of this, we also mark locals as // conflicting when both of them are written to in the same // statement. - if self.live.contains(q) || writes.contains(&q) { - CandidateFilter::Remove + if self.live.contains(q) || writes.iter().any(|&(x, _)| x == q) { + modification } else { - CandidateFilter::Keep + CandidateModification::Keep } }, self.at, @@ -519,7 +568,9 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> { /// Describes where a statement/terminator writes to #[derive(Default, Debug)] struct WriteInfo { - writes: Vec, + /// Which locals are written to. The `bool` is true if the write is "removable," ie if it comes + /// from a `Operand::Move` or `Deinit`. + writes: Vec<(Local, bool)>, /// If this pair of locals is a candidate pair, completely skip processing it during this /// statement. All other candidates are unaffected. skip_pair: Option<(Local, Local)>, @@ -563,10 +614,11 @@ impl WriteInfo { | Rvalue::CopyForDeref(_) => (), } } + StatementKind::Deinit(p) => { + self.writes.push((p.local, true)); + } // Retags are technically also reads, but reporting them as a write suffices - StatementKind::SetDiscriminant { place, .. } - | StatementKind::Deinit(place) - | StatementKind::Retag(_, place) => { + StatementKind::SetDiscriminant { place, .. } | StatementKind::Retag(_, place) => { self.add_place(**place); } StatementKind::Intrinsic(_) @@ -652,16 +704,12 @@ impl WriteInfo { } fn add_place<'tcx>(&mut self, place: Place<'tcx>) { - self.writes.push(place.local); + self.writes.push((place.local, false)); } fn add_operand<'tcx>(&mut self, op: &Operand<'tcx>) { match op { - // FIXME(JakobDegen): In a previous version, the `Move` case was incorrectly treated as - // being a read only. This was unsound, however we cannot add a regression test because - // it is not possible to set this off with current MIR. Once we have that ability, a - // regression test should be added. - Operand::Move(p) => self.add_place(*p), + Operand::Move(p) => self.writes.push((p.local, true)), Operand::Copy(_) | Operand::Constant(_) => (), } } @@ -716,7 +764,7 @@ fn places_to_candidate_pair<'tcx>( fn find_candidates<'alloc, 'tcx>( body: &Body<'tcx>, borrowed: &BitSet, - candidates: &'alloc mut FxHashMap>, + candidates: &'alloc mut FxHashMap)>>, candidates_reverse: &'alloc mut FxHashMap>, ) -> Candidates<'alloc> { candidates.clear(); @@ -730,8 +778,8 @@ fn find_candidates<'alloc, 'tcx>( } // Generate the reverse map for (src, cands) in candidates.iter() { - for dest in cands.iter().copied() { - candidates_reverse.entry(dest).or_default().push(*src); + for (dest, _) in cands.iter() { + candidates_reverse.entry(*dest).or_default().push(*src); } } Candidates { c: candidates, reverse: candidates_reverse } @@ -739,7 +787,7 @@ fn find_candidates<'alloc, 'tcx>( struct FindAssignments<'a, 'alloc, 'tcx> { body: &'a Body<'tcx>, - candidates: &'alloc mut FxHashMap>, + candidates: &'alloc mut FxHashMap)>>, borrowed: &'a BitSet, } @@ -766,7 +814,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> { } // We may insert duplicates here, but that's fine - self.candidates.entry(src).or_default().push(dest); + self.candidates.entry(src).or_default().push((dest, Vec::new())); } } } diff --git a/src/test/mir-opt/dest-prop/move.move_simple.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/move.move_simple.DestinationPropagation.diff new file mode 100644 index 0000000000000..bfb5c359fcc71 --- /dev/null +++ b/src/test/mir-opt/dest-prop/move.move_simple.DestinationPropagation.diff @@ -0,0 +1,38 @@ +- // MIR for `move_simple` before DestinationPropagation ++ // MIR for `move_simple` after DestinationPropagation + + fn move_simple(_1: i32) -> () { + debug x => _1; // in scope 0 at $DIR/move.rs:+0:16: +0:17 + let mut _0: (); // return place in scope 0 at $DIR/move.rs:+0:24: +0:24 + let _2: (); // in scope 0 at $DIR/move.rs:+1:5: +1:19 + let mut _3: i32; // in scope 0 at $DIR/move.rs:+1:14: +1:15 + let mut _4: i32; // in scope 0 at $DIR/move.rs:+1:17: +1:18 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/move.rs:+1:5: +1:19 +- StorageLive(_3); // scope 0 at $DIR/move.rs:+1:14: +1:15 +- _3 = _1; // scope 0 at $DIR/move.rs:+1:14: +1:15 +- StorageLive(_4); // scope 0 at $DIR/move.rs:+1:17: +1:18 +- _4 = _1; // scope 0 at $DIR/move.rs:+1:17: +1:18 +- _2 = use_both(move _3, move _4) -> bb1; // scope 0 at $DIR/move.rs:+1:5: +1:19 ++ nop; // scope 0 at $DIR/move.rs:+1:14: +1:15 ++ nop; // scope 0 at $DIR/move.rs:+1:14: +1:15 ++ nop; // scope 0 at $DIR/move.rs:+1:17: +1:18 ++ nop; // scope 0 at $DIR/move.rs:+1:17: +1:18 ++ _2 = use_both(_1, _1) -> bb1; // scope 0 at $DIR/move.rs:+1:5: +1:19 + // mir::Constant + // + span: $DIR/move.rs:8:5: 8:13 + // + literal: Const { ty: fn(i32, i32) {use_both}, val: Value() } + } + + bb1: { +- StorageDead(_4); // scope 0 at $DIR/move.rs:+1:18: +1:19 +- StorageDead(_3); // scope 0 at $DIR/move.rs:+1:18: +1:19 ++ nop; // scope 0 at $DIR/move.rs:+1:18: +1:19 ++ nop; // scope 0 at $DIR/move.rs:+1:18: +1:19 + StorageDead(_2); // scope 0 at $DIR/move.rs:+1:19: +1:20 + _0 = const (); // scope 0 at $DIR/move.rs:+0:24: +2:2 + return; // scope 0 at $DIR/move.rs:+2:2: +2:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/move.rs b/src/test/mir-opt/dest-prop/move.rs new file mode 100644 index 0000000000000..88c2a2c9347dc --- /dev/null +++ b/src/test/mir-opt/dest-prop/move.rs @@ -0,0 +1,13 @@ +// unit-test: DestinationPropagation + +#[inline(never)] +fn use_both(_: i32, _: i32) {} + +// EMIT_MIR move.move_simple.DestinationPropagation.diff +fn move_simple(x: i32) { + use_both(x, x); +} + +fn main() { + move_simple(1); +} diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir index e0d6b58f229c4..1ebcbd3146a5f 100644 --- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir +++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir @@ -5,21 +5,20 @@ fn num_to_digit(_1: char) -> u32 { let mut _0: u32; // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38 let mut _2: std::option::Option; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41 let mut _3: u32; // in scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 - let mut _9: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _8: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 1 (inlined char::methods::::is_digit) { // at $DIR/issue_59352.rs:14:8: 14:23 debug self => _1; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL debug radix => _3; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL let mut _4: &std::option::Option; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL let _5: std::option::Option; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - let mut _6: char; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL scope 2 (inlined Option::::is_some) { // at $SRC_DIR/core/src/char/methods.rs:LL:COL debug self => _4; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL } } scope 3 (inlined #[track_caller] Option::::unwrap) { // at $DIR/issue_59352.rs:14:26: 14:50 debug self => _2; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _7: isize; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - let mut _8: !; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _6: isize; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _7: !; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL scope 4 { debug val => _0; // in scope 4 at $SRC_DIR/core/src/option.rs:LL:COL } @@ -29,9 +28,7 @@ fn num_to_digit(_1: char) -> u32 { StorageLive(_3); // scope 0 at $DIR/issue_59352.rs:+2:8: +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 - StorageLive(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _6 = _1; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _5 = char::methods::::to_digit(move _6, 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) -> bb5; // 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() } @@ -46,8 +43,8 @@ fn num_to_digit(_1: char) -> u32 { } 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 + _6 = discriminant(_2); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _6) -> [0: bb6, 1: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL } bb3: { @@ -61,17 +58,16 @@ fn num_to_digit(_1: char) -> u32 { bb5: { _4 = &_5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - StorageDead(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL - _9 = discriminant((*_4)); // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + _8 = 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:8: +2:23 - switchInt(move _9) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 + switchInt(move _8) -> [1: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23 } bb6: { - StorageLive(_8); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL - _8 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + StorageLive(_7); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL + _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/option.rs:LL:COL // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value() } diff --git a/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir index 701c2ad705af2..dee1d538395ef 100644 --- a/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir +++ b/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir @@ -5,27 +5,23 @@ fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55 let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72 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 mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 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 + StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +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 + _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 } bb2: { diff --git a/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir index 0440cfce2893f..e35fe758ab12d 100644 --- a/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir +++ b/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir @@ -5,30 +5,26 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { 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 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + let mut _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + let mut _9: 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 + StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +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 + _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 } bb2: { @@ -37,16 +33,16 @@ fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { } 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 + StorageLive(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + _7 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + _8 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + _9 = Lt(const 0_usize, _8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, 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 + (*_2)[_7] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22 + StorageDead(_7); // 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 } diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir index 1556c240dc57a..d37c258216064 100644 --- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir +++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir @@ -4,9 +4,7 @@ fn while_loop(_1: bool) -> () { debug c => _1; // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16 let mut _0: (); // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24 let mut _2: bool; // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22 - let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - let mut _4: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23 - let mut _5: bool; // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22 + let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23 bb0: { goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 @@ -14,41 +12,35 @@ fn while_loop(_1: bool) -> () { bb1: { StorageLive(_2); // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 - StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - _3 = _1; // scope 0 at $DIR/while_storage.rs:+1:20: +1:21 - _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 + _2 = get_bool(_1) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 // mir::Constant // + span: $DIR/while_storage.rs:10:11: 10:19 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() } } bb2: { - StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+1:21: +1:22 switchInt(move _2) -> [0: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22 } bb3: { - StorageLive(_4); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 - StorageLive(_5); // scope 0 at $DIR/while_storage.rs:+2:21: +2:22 - _5 = _1; // scope 0 at $DIR/while_storage.rs:+2:21: +2:22 - _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + _3 = get_bool(_1) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 // mir::Constant // + span: $DIR/while_storage.rs:11:12: 11:20 // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value() } } bb4: { - StorageDead(_5); // scope 0 at $DIR/while_storage.rs:+2:22: +2:23 - switchInt(move _4) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 + switchInt(move _3) -> [0: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23 } bb5: { - StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 + StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 goto -> bb8; // scope 0 at no-location } bb6: { - StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 + StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10 StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6 goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6 }