From 0843acbea6441d5d4a07576ba206ccc01949662a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 4 Feb 2023 14:39:42 +0000 Subject: [PATCH 1/7] Fix SROA without deaggregation. --- compiler/rustc_mir_transform/src/sroa.rs | 127 +++++++++++------- .../const_debuginfo.main.ConstDebugInfo.diff | 30 ++--- ...variable_unprop_assign.main.ConstProp.diff | 41 +++--- ...es_into_variable.main.ConstProp.64bit.diff | 12 +- ...o_variable.main.PreCodegen.after.64bit.mir | 4 +- ...n.ScalarReplacementOfAggregates.64bit.diff | 16 ++- ....main.SimplifyLocals-final.after.64bit.mir | 4 +- ..._option_map_e2e.ezmap.PreCodegen.after.mir | 14 +- ...oa.flat.ScalarReplacementOfAggregates.diff | 37 ++++- ...structs.ScalarReplacementOfAggregates.diff | 16 ++- 10 files changed, 174 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 42124f5a4808d..2118e3c552224 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -2,6 +2,7 @@ use crate::MirPass; use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; +use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -13,7 +14,9 @@ impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates { sess.mir_opt_level() >= 3 } + #[instrument(level = "debug", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!(def_id = ?body.source.def_id()); let escaping = escaping_locals(&*body); debug!(?escaping); let replacements = compute_flattening(tcx, body, escaping); @@ -69,15 +72,28 @@ fn escaping_locals(body: &Body<'_>) -> BitSet { self.super_rvalue(rvalue, location) } + fn visit_assign( + &mut self, + lvalue: &Place<'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location, + ) { + if lvalue.as_local().is_some() && let Rvalue::Aggregate(..) = rvalue { + // Aggregate assignments are expanded in run_pass. + self.visit_rvalue(rvalue, location); + return; + } + self.super_assign(lvalue, rvalue, location) + } + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - if let StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Deinit(..) = statement.kind - { + match statement.kind { // Storage statements are expanded in run_pass. - return; + StatementKind::StorageLive(..) + | StatementKind::StorageDead(..) + | StatementKind::Deinit(..) => return, + _ => self.super_statement(statement, location), } - self.super_statement(statement, location) } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { @@ -192,6 +208,7 @@ fn replace_flattened_locals<'tcx>( replacements, all_dead_locals, fragments, + patch: MirPatch::new(body), }; for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { visitor.visit_basic_block_data(bb, data); @@ -205,6 +222,7 @@ fn replace_flattened_locals<'tcx>( for var_debug_info in &mut body.var_debug_info { visitor.visit_var_debug_info(var_debug_info); } + visitor.patch.apply(body); } struct ReplacementVisitor<'tcx, 'll> { @@ -218,6 +236,7 @@ struct ReplacementVisitor<'tcx, 'll> { /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage /// and deinit statement and debuginfo. fragments: IndexVec], Local)>>, + patch: MirPatch<'tcx>, } impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { @@ -255,12 +274,63 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { - if let StatementKind::StorageLive(..) - | StatementKind::StorageDead(..) - | StatementKind::Deinit(..) = statement.kind - { - // Storage statements are expanded in run_pass. - return; + match statement.kind { + StatementKind::StorageLive(l) => { + if self.all_dead_locals.contains(l) { + let final_locals = &self.fragments[l]; + for &(_, fl) in final_locals { + self.patch.add_statement(location, StatementKind::StorageLive(fl)); + } + statement.make_nop(); + } + return; + } + StatementKind::StorageDead(l) => { + if self.all_dead_locals.contains(l) { + let final_locals = &self.fragments[l]; + for &(_, fl) in final_locals { + self.patch.add_statement(location, StatementKind::StorageDead(fl)); + } + statement.make_nop(); + } + return; + } + StatementKind::Deinit(box ref place) => { + if let Some(local) = place.as_local() + && self.all_dead_locals.contains(local) + { + let final_locals = &self.fragments[local]; + for &(_, fl) in final_locals { + self.patch.add_statement( + location, + StatementKind::Deinit(Box::new(fl.into())), + ); + } + statement.make_nop(); + return; + } + } + + StatementKind::Assign(box (ref place, Rvalue::Aggregate(_, ref operands))) => { + if let Some(local) = place.as_local() + && self.all_dead_locals.contains(local) + { + let final_locals = &self.fragments[local]; + for &(projection, fl) in final_locals { + let &[PlaceElem::Field(index, _)] = projection else { bug!() }; + let index = index.as_usize(); + let rvalue = Rvalue::Use(operands[index].clone()); + self.patch.add_statement( + location, + StatementKind::Assign(Box::new((fl.into(), rvalue))), + ); + } + statement.make_nop(); + return; + } + } + + _ => {} } self.super_statement(statement, location) } @@ -309,39 +379,6 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } } - fn visit_basic_block_data(&mut self, bb: BasicBlock, bbdata: &mut BasicBlockData<'tcx>) { - self.super_basic_block_data(bb, bbdata); - - #[derive(Debug)] - enum Stmt { - StorageLive, - StorageDead, - Deinit, - } - - bbdata.expand_statements(|stmt| { - let source_info = stmt.source_info; - let (stmt, origin_local) = match &stmt.kind { - StatementKind::StorageLive(l) => (Stmt::StorageLive, *l), - StatementKind::StorageDead(l) => (Stmt::StorageDead, *l), - StatementKind::Deinit(p) if let Some(l) = p.as_local() => (Stmt::Deinit, l), - _ => return None, - }; - if !self.all_dead_locals.contains(origin_local) { - return None; - } - let final_locals = self.fragments.get(origin_local)?; - Some(final_locals.iter().map(move |&(_, l)| { - let kind = match stmt { - Stmt::StorageLive => StatementKind::StorageLive(l), - Stmt::StorageDead => StatementKind::StorageDead(l), - Stmt::Deinit => StatementKind::Deinit(Box::new(l.into())), - }; - Statement { source_info, kind } - })) - }); - } - fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { assert!(!self.all_dead_locals.contains(*local)); } diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index 49e8b020dfb79..e14e586f34b09 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -8,8 +8,8 @@ let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:15: +4:16 let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:19: +4:20 let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:23: +4:24 - let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16 - let mut _15: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22 + let mut _13: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16 + let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22 scope 1 { - debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10 + debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10 @@ -35,12 +35,13 @@ let _11: std::option::Option; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 scope 7 { debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10 - let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _15: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _16: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 scope 8 { - debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 - let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 + debug p => Point{ .0 => _15, .1 => _16, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _12: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 scope 9 { -- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 +- debug a => _12; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 + debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 } } @@ -70,18 +71,11 @@ _10 = (const true, const false, const 123_u32); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 _11 = Option::::Some(const 99_u16); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 - StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 - _12 = Point { x: const 32_u32, y: const 32_u32 }; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 - StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16 - _14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:16 - StorageLive(_15); // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22 - _15 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:19: +13:22 - _13 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22 - StorageDead(_15); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22 - StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:+13:21: +13:22 - StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:+14:1: +14:2 + _15 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + _16 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + StorageLive(_12); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 + _12 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22 + StorageDead(_12); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2 diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index a2e4890c6a64c..8bd589fb2c877 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -4,18 +4,19 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +0:11 let _1: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 - let mut _3: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 + let mut _2: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 scope 1 { debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+1:9: +1:10 - let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + let mut _5: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + let mut _6: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 scope 2 { - debug x => _2; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 - let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 + debug x => (i32, i32){ .1 => _5, .0 => _6, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + let _3: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 scope 3 { - debug y => _4; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 - let _5: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 + debug y => _3; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 + let _4: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 scope 4 { - debug z => _5; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 + debug z => _6; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 } } } @@ -30,21 +31,17 @@ } bb1: { - StorageLive(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 -- _2 = (const 1_i32, const 2_i32); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 -+ _2 = const (1_i32, 2_i32); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - _3 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - (_2.1: i32) = move _3; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 - StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 - _4 = (_2.1: i32); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 - StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 -- _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 -+ _5 = const 1_i32; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 - StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_2); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 + StorageLive(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + _5 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + _6 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + StorageLive(_2); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 + _2 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 + _5 = move _2; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 + StorageDead(_2); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 + StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 + _3 = _5; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 + StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 + StorageDead(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2 } diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 1368b114658df..691aa01a56408 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -9,7 +9,7 @@ let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _9: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -17,7 +17,7 @@ debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 scope 3 { - debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug z => _9; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 } } } @@ -50,13 +50,7 @@ + _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 - StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 -+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 - StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + _9 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir b/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir index 9db87cfc879bb..81cfd22db6c50 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.64bit.mir @@ -3,12 +3,12 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _3: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 scope 2 { debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 scope 3 { debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 } @@ -18,8 +18,6 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff b/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff index de1d57ed401a1..87271f24fc429 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff @@ -10,6 +10,7 @@ let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -45,10 +46,17 @@ StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 +- StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 +- StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _10 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _8 = _10; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 ++ StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir b/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir index d926b9df73317..002e914e8fa16 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.64bit.mir @@ -3,12 +3,12 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _3: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 scope 2 { debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 scope 3 { debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 } @@ -18,8 +18,6 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4: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 5c898d798ff16..e338f15b48531 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 @@ -4,25 +4,22 @@ fn ezmap(_1: Option) -> Option { debug x => _1; // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15 let mut _0: std::option::Option; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44 let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21 - let mut _7: i32; // in scope 0 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 scope 1 (inlined map::) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22 debug slf => _1; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20 debug f => _2; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34 let mut _3: isize; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16 let _4: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 let mut _5: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - let mut _6: (i32,); // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 scope 2 { debug x => _4; // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - debug n => _7; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14 + debug n => _4; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14 } } } bb0: { StorageLive(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21 - StorageLive(_4); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:5: +1:22 _3 = discriminant(_1); // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14 switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14 } @@ -39,20 +36,13 @@ fn ezmap(_1: Option) -> Option { bb3: { _4 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15 StorageLive(_5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - StorageLive(_6); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - _6 = (move _4,); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - StorageLive(_7); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - _7 = move (_6.0: i32); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - _5 = Add(_7, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 - StorageDead(_7); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29 - StorageDead(_6); // scope 2 at $DIR/simple_option_map_e2e.rs:7:28: 7:29 + _5 = Add(_4, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21 _0 = Option::::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30 StorageDead(_5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30 goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2 } bb4: { - StorageDead(_4); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:5: +1:22 StorageDead(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22 return; // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff index 749c22c26e04b..338ce262f1ec9 100644 --- a/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff @@ -10,6 +10,10 @@ let mut _5: Foo; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 let mut _6: (); // in scope 0 at $DIR/sroa.rs:+1:45: +1:47 let mut _7: std::option::Option; // in scope 0 at $DIR/sroa.rs:+1:60: +1:68 ++ let mut _8: u8; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ let mut _9: (); // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ let mut _10: &str; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ let mut _11: std::option::Option; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70 scope 1 { debug a => _1; // in scope 1 at $DIR/sroa.rs:+1:15: +1:16 debug b => _2; // in scope 1 at $DIR/sroa.rs:+1:18: +1:19 @@ -26,26 +30,45 @@ } bb0: { - StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 +- StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_8); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_9); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_10); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ StorageLive(_11); // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ nop; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:45: +1:47 _6 = (); // scope 0 at $DIR/sroa.rs:+1:45: +1:47 StorageLive(_7); // scope 0 at $DIR/sroa.rs:+1:60: +1:68 _7 = Option::::Some(const -4_isize); // scope 0 at $DIR/sroa.rs:+1:60: +1:68 - _5 = Foo { a: const 5_u8, b: move _6, c: const "a", d: move _7 }; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 +- _5 = Foo { a: const 5_u8, b: move _6, c: const "a", d: move _7 }; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _8 = const 5_u8; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _9 = move _6; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ _10 = const "a"; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 // mir::Constant // + span: $DIR/sroa.rs:57:52: 57:55 // + literal: Const { ty: &str, val: Value(Slice(..)) } ++ _11 = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 ++ nop; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 StorageDead(_7); // scope 0 at $DIR/sroa.rs:+1:69: +1:70 StorageDead(_6); // scope 0 at $DIR/sroa.rs:+1:69: +1:70 StorageLive(_1); // scope 0 at $DIR/sroa.rs:+1:15: +1:16 - _1 = (_5.0: u8); // scope 0 at $DIR/sroa.rs:+1:15: +1:16 +- _1 = (_5.0: u8); // scope 0 at $DIR/sroa.rs:+1:15: +1:16 ++ _1 = _8; // scope 0 at $DIR/sroa.rs:+1:15: +1:16 StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:18: +1:19 - _2 = (_5.1: ()); // scope 0 at $DIR/sroa.rs:+1:18: +1:19 +- _2 = (_5.1: ()); // scope 0 at $DIR/sroa.rs:+1:18: +1:19 ++ _2 = _9; // scope 0 at $DIR/sroa.rs:+1:18: +1:19 StorageLive(_3); // scope 0 at $DIR/sroa.rs:+1:21: +1:22 - _3 = (_5.2: &str); // scope 0 at $DIR/sroa.rs:+1:21: +1:22 +- _3 = (_5.2: &str); // scope 0 at $DIR/sroa.rs:+1:21: +1:22 ++ _3 = _10; // scope 0 at $DIR/sroa.rs:+1:21: +1:22 StorageLive(_4); // scope 0 at $DIR/sroa.rs:+1:24: +1:25 - _4 = (_5.3: std::option::Option); // scope 0 at $DIR/sroa.rs:+1:24: +1:25 - StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 +- _4 = (_5.3: std::option::Option); // scope 0 at $DIR/sroa.rs:+1:24: +1:25 +- StorageDead(_5); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ _4 = _11; // scope 0 at $DIR/sroa.rs:+1:24: +1:25 ++ StorageDead(_8); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ StorageDead(_9); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ StorageDead(_10); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ StorageDead(_11); // scope 0 at $DIR/sroa.rs:+1:70: +1:71 ++ nop; // scope 0 at $DIR/sroa.rs:+1:70: +1:71 _0 = const (); // scope 0 at $DIR/sroa.rs:+0:15: +6:2 StorageDead(_4); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 diff --git a/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff index dc4945104f4cb..ca3cb3d8ed139 100644 --- a/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff @@ -6,15 +6,23 @@ let mut _0: f32; // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:30 let mut _2: structs::U; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 let mut _3: f32; // in scope 0 at $DIR/sroa.rs:+6:18: +6:19 ++ let mut _4: f32; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 bb0: { - StorageLive(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 +- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ StorageLive(_4); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ nop; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 StorageLive(_3); // scope 0 at $DIR/sroa.rs:+6:18: +6:19 _3 = _1; // scope 0 at $DIR/sroa.rs:+6:18: +6:19 - _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 +- _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ _4 = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ nop; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:20: +6:21 - _0 = (_2.1: f32); // scope 0 at $DIR/sroa.rs:+6:5: +6:23 - StorageDead(_2); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 +- _0 = (_2.1: f32); // scope 0 at $DIR/sroa.rs:+6:5: +6:23 +- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 ++ _0 = _4; // scope 0 at $DIR/sroa.rs:+6:5: +6:23 ++ StorageDead(_4); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 ++ nop; // scope 0 at $DIR/sroa.rs:+7:1: +7:2 return; // scope 0 at $DIR/sroa.rs:+7:2: +7:2 } } From dc4fe8e2953747605b085d297cf329824d499884 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Feb 2023 09:31:27 +0000 Subject: [PATCH 2/7] Make SROA expand assignments. --- compiler/rustc_mir_transform/src/sroa.rs | 88 ++++++++++++++----- ....copies.ScalarReplacementOfAggregates.diff | 48 ++++++++++ ...scaping.ScalarReplacementOfAggregates.diff | 4 +- ...oa.flat.ScalarReplacementOfAggregates.diff | 2 +- ..._copies.ScalarReplacementOfAggregates.diff | 48 ++++++++++ tests/mir-opt/sroa.rs | 30 +++++-- 6 files changed, 188 insertions(+), 32 deletions(-) create mode 100644 tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff create mode 100644 tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 2118e3c552224..f6609704d25d4 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -78,10 +78,15 @@ fn escaping_locals(body: &Body<'_>) -> BitSet { rvalue: &Rvalue<'tcx>, location: Location, ) { - if lvalue.as_local().is_some() && let Rvalue::Aggregate(..) = rvalue { - // Aggregate assignments are expanded in run_pass. - self.visit_rvalue(rvalue, location); - return; + if lvalue.as_local().is_some() { + match rvalue { + // Aggregate assignments are expanded in run_pass. + Rvalue::Aggregate(..) | Rvalue::Use(..) => { + self.visit_rvalue(rvalue, location); + return; + } + _ => {} + } } self.super_assign(lvalue, rvalue, location) } @@ -195,10 +200,9 @@ fn replace_flattened_locals<'tcx>( return; } - let mut fragments = IndexVec::new(); + let mut fragments = IndexVec::<_, Option>>::from_elem(None, &body.local_decls); for (k, v) in &replacements.fields { - fragments.ensure_contains_elem(k.local, || Vec::new()); - fragments[k.local].push((k.projection, *v)); + fragments[k.local].get_or_insert_default().push((k.projection, *v)); } debug!(?fragments); @@ -235,7 +239,7 @@ struct ReplacementVisitor<'tcx, 'll> { all_dead_locals: BitSet, /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage /// and deinit statement and debuginfo. - fragments: IndexVec], Local)>>, + fragments: IndexVec], Local)>>>, patch: MirPatch<'tcx>, } @@ -243,9 +247,9 @@ impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { fn gather_debug_info_fragments( &self, place: PlaceRef<'tcx>, - ) -> Vec> { + ) -> Option>> { let mut fragments = Vec::new(); - let parts = &self.fragments[place.local]; + let Some(parts) = &self.fragments[place.local] else { return None }; for (proj, replacement_local) in parts { if proj.starts_with(place.projection) { fragments.push(VarDebugInfoFragment { @@ -254,7 +258,7 @@ impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { }); } } - fragments + Some(fragments) } fn replace_place(&self, place: PlaceRef<'tcx>) -> Option> { @@ -276,8 +280,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { match statement.kind { StatementKind::StorageLive(l) => { - if self.all_dead_locals.contains(l) { - let final_locals = &self.fragments[l]; + if let Some(final_locals) = &self.fragments[l] { for &(_, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageLive(fl)); } @@ -286,8 +289,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { return; } StatementKind::StorageDead(l) => { - if self.all_dead_locals.contains(l) { - let final_locals = &self.fragments[l]; + if let Some(final_locals) = &self.fragments[l] { for &(_, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageDead(fl)); } @@ -297,9 +299,8 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } StatementKind::Deinit(box ref place) => { if let Some(local) = place.as_local() - && self.all_dead_locals.contains(local) + && let Some(final_locals) = &self.fragments[local] { - let final_locals = &self.fragments[local]; for &(_, fl) in final_locals { self.patch.add_statement( location, @@ -313,9 +314,8 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { StatementKind::Assign(box (ref place, Rvalue::Aggregate(_, ref operands))) => { if let Some(local) = place.as_local() - && self.all_dead_locals.contains(local) + && let Some(final_locals) = &self.fragments[local] { - let final_locals = &self.fragments[local]; for &(projection, fl) in final_locals { let &[PlaceElem::Field(index, _)] = projection else { bug!() }; let index = index.as_usize(); @@ -330,6 +330,48 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } } + StatementKind::Assign(box (ref place, Rvalue::Use(Operand::Constant(_)))) => { + if let Some(local) = place.as_local() + && let Some(final_locals) = &self.fragments[local] + { + for &(projection, fl) in final_locals { + let rvalue = Rvalue::Use(Operand::Move(place.project_deeper(projection, self.tcx))); + self.patch.add_statement( + location, + StatementKind::Assign(Box::new((fl.into(), rvalue))), + ); + } + self.all_dead_locals.remove(local); + return; + } + } + + StatementKind::Assign(box (ref lhs, Rvalue::Use(ref op))) => { + let (rplace, copy) = match op { + Operand::Copy(rplace) => (rplace, true), + Operand::Move(rplace) => (rplace, false), + Operand::Constant(_) => bug!(), + }; + if let Some(local) = lhs.as_local() + && let Some(final_locals) = &self.fragments[local] + { + for &(projection, fl) in final_locals { + let rplace = rplace.project_deeper(projection, self.tcx); + let rvalue = if copy { + Rvalue::Use(Operand::Copy(rplace)) + } else { + Rvalue::Use(Operand::Move(rplace)) + }; + self.patch.add_statement( + location, + StatementKind::Assign(Box::new((fl.into(), rvalue))), + ); + } + statement.make_nop(); + return; + } + } + _ => {} } self.super_statement(statement, location) @@ -348,9 +390,8 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { VarDebugInfoContents::Place(ref mut place) => { if let Some(repl) = self.replace_place(place.as_ref()) { *place = repl; - } else if self.all_dead_locals.contains(place.local) { + } else if let Some(fragments) = self.gather_debug_info_fragments(place.as_ref()) { let ty = place.ty(self.local_decls, self.tcx).ty; - let fragments = self.gather_debug_info_fragments(place.as_ref()); var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; } } @@ -361,8 +402,9 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { if let Some(repl) = self.replace_place(fragment.contents.as_ref()) { fragment.contents = repl; true - } else if self.all_dead_locals.contains(fragment.contents.local) { - let frg = self.gather_debug_info_fragments(fragment.contents.as_ref()); + } else if let Some(frg) = + self.gather_debug_info_fragments(fragment.contents.as_ref()) + { new_fragments.extend(frg.into_iter().map(|mut f| { f.projection.splice(0..0, fragment.projection.iter().copied()); f diff --git a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff new file mode 100644 index 0000000000000..72610de8eafa3 --- /dev/null +++ b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff @@ -0,0 +1,48 @@ +- // MIR for `copies` before ScalarReplacementOfAggregates ++ // MIR for `copies` after ScalarReplacementOfAggregates + + fn copies(_1: Foo) -> () { + debug x => _1; // in scope 0 at $DIR/sroa.rs:+0:11: +0:12 + let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19 + let _2: Foo; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _5: u8; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _6: &str; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 + scope 1 { +- debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 ++ debug y => Foo{ .0 => _5, .2 => _6, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 + let _3: u8; // in scope 1 at $DIR/sroa.rs:+2:9: +2:10 + scope 2 { + debug t => _3; // in scope 2 at $DIR/sroa.rs:+2:9: +2:10 + let _4: &str; // in scope 2 at $DIR/sroa.rs:+3:9: +3:10 + scope 3 { + debug u => _4; // in scope 3 at $DIR/sroa.rs:+3:9: +3:10 + } + } + } + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 +- _2 = _1; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ nop; // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ _5 = (_1.0: u8); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ _6 = (_1.2: &str); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ nop; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 + StorageLive(_3); // scope 1 at $DIR/sroa.rs:+2:9: +2:10 +- _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 ++ _3 = _5; // scope 1 at $DIR/sroa.rs:+2:13: +2:16 + StorageLive(_4); // scope 2 at $DIR/sroa.rs:+3:9: +3:10 +- _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 ++ _4 = _6; // scope 2 at $DIR/sroa.rs:+3:13: +3:16 + _0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +4:2 + StorageDead(_4); // scope 2 at $DIR/sroa.rs:+4:1: +4:2 + StorageDead(_3); // scope 1 at $DIR/sroa.rs:+4:1: +4:2 +- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ StorageDead(_5); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ StorageDead(_6); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ nop; // scope 0 at $DIR/sroa.rs:+4:1: +4:2 + return; // scope 0 at $DIR/sroa.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff index b01fb6fc91538..ea7f500722451 100644 --- a/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff @@ -17,7 +17,7 @@ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+2:34: +2:37 _5 = g() -> bb1; // scope 0 at $DIR/sroa.rs:+2:34: +2:37 // mir::Constant - // + span: $DIR/sroa.rs:78:34: 78:35 + // + span: $DIR/sroa.rs:73:34: 73:35 // + literal: Const { ty: fn() -> u32 {g}, val: Value() } } @@ -28,7 +28,7 @@ _2 = &raw const (*_3); // scope 0 at $DIR/sroa.rs:+2:7: +2:41 _1 = f(move _2) -> bb2; // scope 0 at $DIR/sroa.rs:+2:5: +2:42 // mir::Constant - // + span: $DIR/sroa.rs:78:5: 78:6 + // + span: $DIR/sroa.rs:73:5: 73:6 // + literal: Const { ty: fn(*const u32) {f}, val: Value() } } diff --git a/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff index 338ce262f1ec9..69631fc0213f8 100644 --- a/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff @@ -45,7 +45,7 @@ + _9 = move _6; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 + _10 = const "a"; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 // mir::Constant - // + span: $DIR/sroa.rs:57:52: 57:55 + // + span: $DIR/sroa.rs:53:52: 53:55 // + literal: Const { ty: &str, val: Value(Slice(..)) } + _11 = move _7; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 + nop; // scope 0 at $DIR/sroa.rs:+1:30: +1:70 diff --git a/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff new file mode 100644 index 0000000000000..1a561a9edde30 --- /dev/null +++ b/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff @@ -0,0 +1,48 @@ +- // MIR for `ref_copies` before ScalarReplacementOfAggregates ++ // MIR for `ref_copies` after ScalarReplacementOfAggregates + + fn ref_copies(_1: &Foo) -> () { + debug x => _1; // in scope 0 at $DIR/sroa.rs:+0:15: +0:16 + let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:24: +0:24 + let _2: Foo; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _5: u8; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _6: &str; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 + scope 1 { +- debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 ++ debug y => Foo{ .0 => _5, .2 => _6, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 + let _3: u8; // in scope 1 at $DIR/sroa.rs:+2:9: +2:10 + scope 2 { + debug t => _3; // in scope 2 at $DIR/sroa.rs:+2:9: +2:10 + let _4: &str; // in scope 2 at $DIR/sroa.rs:+3:9: +3:10 + scope 3 { + debug u => _4; // in scope 3 at $DIR/sroa.rs:+3:9: +3:10 + } + } + } + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 +- _2 = (*_1); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 ++ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ nop; // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ _5 = ((*_1).0: u8); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 ++ _6 = ((*_1).2: &str); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 ++ nop; // scope 0 at $DIR/sroa.rs:+1:13: +1:15 + StorageLive(_3); // scope 1 at $DIR/sroa.rs:+2:9: +2:10 +- _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 ++ _3 = _5; // scope 1 at $DIR/sroa.rs:+2:13: +2:16 + StorageLive(_4); // scope 2 at $DIR/sroa.rs:+3:9: +3:10 +- _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 ++ _4 = _6; // scope 2 at $DIR/sroa.rs:+3:13: +3:16 + _0 = const (); // scope 0 at $DIR/sroa.rs:+0:24: +4:2 + StorageDead(_4); // scope 2 at $DIR/sroa.rs:+4:1: +4:2 + StorageDead(_3); // scope 1 at $DIR/sroa.rs:+4:1: +4:2 +- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ StorageDead(_5); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ StorageDead(_6); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ nop; // scope 0 at $DIR/sroa.rs:+4:1: +4:2 + return; // scope 0 at $DIR/sroa.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/sroa.rs b/tests/mir-opt/sroa.rs index ff8deb40d7d5a..b80f61600c266 100644 --- a/tests/mir-opt/sroa.rs +++ b/tests/mir-opt/sroa.rs @@ -12,17 +12,14 @@ impl Drop for Tag { fn drop(&mut self) {} } -// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff pub fn dropping() { S(Tag(0), Tag(1), Tag(2)).1; } -// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff pub fn enums(a: usize) -> usize { if let Some(a) = Some(a) { a } else { 0 } } -// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff pub fn structs(a: f32) -> f32 { struct U { _foo: usize, @@ -32,7 +29,6 @@ pub fn structs(a: f32) -> f32 { U { _foo: 0, a }.a } -// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff pub fn unions(a: f32) -> u32 { union Repr { f: f32, @@ -41,6 +37,7 @@ pub fn unions(a: f32) -> u32 { unsafe { Repr { f: a }.u } } +#[derive(Copy, Clone)] struct Foo { a: u8, b: (), @@ -52,7 +49,6 @@ fn g() -> u32 { 3 } -// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff pub fn flat() { let Foo { a, b, c, d } = Foo { a: 5, b: (), c: "a", d: Some(-4) }; let _ = a; @@ -72,12 +68,23 @@ fn f(a: *const u32) { println!("{}", unsafe { *a.add(2) }); } -// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff pub fn escaping() { // Verify this struct is not flattened. f(&Escaping { a: 1, b: 2, c: g() }.a); } +fn copies(x: Foo) { + let y = x; + let t = y.a; + let u = y.c; +} + +fn ref_copies(x: &Foo) { + let y = *x; + let t = y.a; + let u = y.c; +} + fn main() { dropping(); enums(5); @@ -85,4 +92,15 @@ fn main() { unions(5.); flat(); escaping(); + copies(Foo { a: 5, b: (), c: "a", d: Some(-4) }); + ref_copies(&Foo { a: 5, b: (), c: "a", d: Some(-4) }); } + +// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.copies.ScalarReplacementOfAggregates.diff +// EMIT_MIR sroa.ref_copies.ScalarReplacementOfAggregates.diff From e465d647b1286e9127dab4df091315588b44dba9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Feb 2023 10:40:21 +0000 Subject: [PATCH 3/7] Introduce helper. --- compiler/rustc_mir_transform/src/sroa.rs | 47 ++++++++++++------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index f6609704d25d4..462c3b4e9184d 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -211,7 +211,7 @@ fn replace_flattened_locals<'tcx>( local_decls: &body.local_decls, replacements, all_dead_locals, - fragments, + fragments: &fragments, patch: MirPatch::new(body), }; for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { @@ -239,7 +239,7 @@ struct ReplacementVisitor<'tcx, 'll> { all_dead_locals: BitSet, /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage /// and deinit statement and debuginfo. - fragments: IndexVec], Local)>>>, + fragments: &'ll IndexVec], Local)>>>, patch: MirPatch<'tcx>, } @@ -270,6 +270,14 @@ impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { None } } + + fn place_fragments( + &self, + place: Place<'tcx>, + ) -> Option<&'ll Vec<(&'tcx [PlaceElem<'tcx>], Local)>> { + let local = place.as_local()?; + self.fragments[local].as_ref() + } } impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { @@ -297,25 +305,19 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } return; } - StatementKind::Deinit(box ref place) => { - if let Some(local) = place.as_local() - && let Some(final_locals) = &self.fragments[local] - { + StatementKind::Deinit(box place) => { + if let Some(final_locals) = self.place_fragments(place) { for &(_, fl) in final_locals { - self.patch.add_statement( - location, - StatementKind::Deinit(Box::new(fl.into())), - ); + self.patch + .add_statement(location, StatementKind::Deinit(Box::new(fl.into()))); } statement.make_nop(); return; } } - StatementKind::Assign(box (ref place, Rvalue::Aggregate(_, ref operands))) => { - if let Some(local) = place.as_local() - && let Some(final_locals) = &self.fragments[local] - { + StatementKind::Assign(box (place, Rvalue::Aggregate(_, ref operands))) => { + if let Some(final_locals) = self.place_fragments(place) { for &(projection, fl) in final_locals { let &[PlaceElem::Field(index, _)] = projection else { bug!() }; let index = index.as_usize(); @@ -330,31 +332,28 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } } - StatementKind::Assign(box (ref place, Rvalue::Use(Operand::Constant(_)))) => { - if let Some(local) = place.as_local() - && let Some(final_locals) = &self.fragments[local] - { + StatementKind::Assign(box (place, Rvalue::Use(Operand::Constant(_)))) => { + if let Some(final_locals) = self.place_fragments(place) { for &(projection, fl) in final_locals { - let rvalue = Rvalue::Use(Operand::Move(place.project_deeper(projection, self.tcx))); + let rvalue = + Rvalue::Use(Operand::Move(place.project_deeper(projection, self.tcx))); self.patch.add_statement( location, StatementKind::Assign(Box::new((fl.into(), rvalue))), ); } - self.all_dead_locals.remove(local); + self.all_dead_locals.remove(place.local); return; } } - StatementKind::Assign(box (ref lhs, Rvalue::Use(ref op))) => { + StatementKind::Assign(box (lhs, Rvalue::Use(ref op))) => { let (rplace, copy) = match op { Operand::Copy(rplace) => (rplace, true), Operand::Move(rplace) => (rplace, false), Operand::Constant(_) => bug!(), }; - if let Some(local) = lhs.as_local() - && let Some(final_locals) = &self.fragments[local] - { + if let Some(final_locals) = self.place_fragments(lhs) { for &(projection, fl) in final_locals { let rplace = rplace.project_deeper(projection, self.tcx); let rvalue = if copy { From 42c95146294c7773ca03e91e945fd545c6ce1ba2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Feb 2023 11:37:44 +0000 Subject: [PATCH 4/7] Simplify construction of replacement map. --- .../rustc_mir_dataflow/src/value_analysis.rs | 2 +- compiler/rustc_mir_transform/src/sroa.rs | 158 ++++++++---------- .../const_debuginfo.main.ConstDebugInfo.diff | 52 +++--- ...ble_variable_aggregate.main.ConstProp.diff | 13 +- ...able_aggregate_mut_ref.main.ConstProp.diff | 10 +- ...variable_unprop_assign.main.ConstProp.diff | 16 +- ...n.ScalarReplacementOfAggregates.64bit.diff | 8 +- ....copies.ScalarReplacementOfAggregates.diff | 69 +++++--- ..._copies.ScalarReplacementOfAggregates.diff | 16 +- tests/mir-opt/sroa.rs | 2 + ...structs.ScalarReplacementOfAggregates.diff | 10 +- 11 files changed, 196 insertions(+), 160 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 6bdbda909d7bd..90d07c81256f5 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -790,7 +790,7 @@ impl TryFrom> for TrackElem { } /// Invokes `f` on all direct fields of `ty`. -fn iter_fields<'tcx>( +pub fn iter_fields<'tcx>( ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, mut f: impl FnMut(Option, Field, Ty<'tcx>), diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 462c3b4e9184d..3cfa0b16499a6 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,11 +1,12 @@ use crate::MirPass; -use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; +use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::value_analysis::iter_fields; pub struct ScalarReplacementOfAggregates; @@ -125,6 +126,36 @@ fn escaping_locals(body: &Body<'_>) -> BitSet { #[derive(Default, Debug)] struct ReplacementMap<'tcx> { fields: FxIndexMap, Local>, + /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage + /// and deinit statement and debuginfo. + fragments: IndexVec], Local)>>>, +} + +impl<'tcx> ReplacementMap<'tcx> { + fn gather_debug_info_fragments( + &self, + place: PlaceRef<'tcx>, + ) -> Option>> { + let mut fragments = Vec::new(); + let Some(parts) = &self.fragments[place.local] else { return None }; + for (proj, replacement_local) in parts { + if proj.starts_with(place.projection) { + fragments.push(VarDebugInfoFragment { + projection: proj[place.projection.len()..].to_vec(), + contents: Place::from(*replacement_local), + }); + } + } + Some(fragments) + } + + fn place_fragments( + &self, + place: Place<'tcx>, + ) -> Option<&Vec<(&'tcx [PlaceElem<'tcx>], Local)>> { + let local = place.as_local()?; + self.fragments[local].as_ref() + } } /// Compute the replacement of flattened places into locals. @@ -136,53 +167,30 @@ fn compute_flattening<'tcx>( body: &mut Body<'tcx>, escaping: BitSet, ) -> ReplacementMap<'tcx> { - let mut visitor = PreFlattenVisitor { - tcx, - escaping, - local_decls: &mut body.local_decls, - map: Default::default(), - }; - for (block, bbdata) in body.basic_blocks.iter_enumerated() { - visitor.visit_basic_block_data(block, bbdata); - } - return visitor.map; - - struct PreFlattenVisitor<'tcx, 'll> { - tcx: TyCtxt<'tcx>, - local_decls: &'ll mut LocalDecls<'tcx>, - escaping: BitSet, - map: ReplacementMap<'tcx>, - } + let mut fields = FxIndexMap::default(); + let mut fragments = IndexVec::from_elem(None::>, &body.local_decls); - impl<'tcx, 'll> PreFlattenVisitor<'tcx, 'll> { - fn create_place(&mut self, place: PlaceRef<'tcx>) { - if self.escaping.contains(place.local) { - return; - } - - match self.map.fields.entry(place) { - IndexEntry::Occupied(_) => {} - IndexEntry::Vacant(v) => { - let ty = place.ty(&*self.local_decls, self.tcx).ty; - let local = self.local_decls.push(LocalDecl { - ty, - user_ty: None, - ..self.local_decls[place.local].clone() - }); - v.insert(local); - } - } - } - } - - impl<'tcx, 'll> Visitor<'tcx> for PreFlattenVisitor<'tcx, 'll> { - fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) { - if let &[PlaceElem::Field(..), ..] = &place.projection[..] { - let pr = PlaceRef { local: place.local, projection: &place.projection[..1] }; - self.create_place(pr) - } + for local in body.local_decls.indices() { + if escaping.contains(local) { + continue; } + let decl = body.local_decls[local].clone(); + let ty = decl.ty; + iter_fields(ty, tcx, |variant, field, field_ty| { + if variant.is_some() { + // Downcasts are currently not supported. + return; + }; + let new_local = + body.local_decls.push(LocalDecl { ty: field_ty, user_ty: None, ..decl.clone() }); + let place = Place::from(local) + .project_deeper(&[PlaceElem::Field(field, field_ty)], tcx) + .as_ref(); + fields.insert(place, new_local); + fragments[local].get_or_insert_default().push((place.projection, new_local)); + }); } + ReplacementMap { fields, fragments } } /// Perform the replacement computed by `compute_flattening`. @@ -200,18 +208,11 @@ fn replace_flattened_locals<'tcx>( return; } - let mut fragments = IndexVec::<_, Option>>::from_elem(None, &body.local_decls); - for (k, v) in &replacements.fields { - fragments[k.local].get_or_insert_default().push((k.projection, *v)); - } - debug!(?fragments); - let mut visitor = ReplacementVisitor { tcx, local_decls: &body.local_decls, replacements, all_dead_locals, - fragments: &fragments, patch: MirPatch::new(body), }; for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { @@ -237,30 +238,10 @@ struct ReplacementVisitor<'tcx, 'll> { replacements: ReplacementMap<'tcx>, /// This is used to check that we are not leaving references to replaced locals behind. all_dead_locals: BitSet, - /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage - /// and deinit statement and debuginfo. - fragments: &'ll IndexVec], Local)>>>, patch: MirPatch<'tcx>, } impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { - fn gather_debug_info_fragments( - &self, - place: PlaceRef<'tcx>, - ) -> Option>> { - let mut fragments = Vec::new(); - let Some(parts) = &self.fragments[place.local] else { return None }; - for (proj, replacement_local) in parts { - if proj.starts_with(place.projection) { - fragments.push(VarDebugInfoFragment { - projection: proj[place.projection.len()..].to_vec(), - contents: Place::from(*replacement_local), - }); - } - } - Some(fragments) - } - fn replace_place(&self, place: PlaceRef<'tcx>) -> Option> { if let &[PlaceElem::Field(..), ref rest @ ..] = place.projection { let pr = PlaceRef { local: place.local, projection: &place.projection[..1] }; @@ -270,14 +251,6 @@ impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { None } } - - fn place_fragments( - &self, - place: Place<'tcx>, - ) -> Option<&'ll Vec<(&'tcx [PlaceElem<'tcx>], Local)>> { - let local = place.as_local()?; - self.fragments[local].as_ref() - } } impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { @@ -285,10 +258,11 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.tcx } + #[instrument(level = "trace", skip(self))] fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { match statement.kind { StatementKind::StorageLive(l) => { - if let Some(final_locals) = &self.fragments[l] { + if let Some(final_locals) = &self.replacements.fragments[l] { for &(_, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageLive(fl)); } @@ -297,7 +271,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { return; } StatementKind::StorageDead(l) => { - if let Some(final_locals) = &self.fragments[l] { + if let Some(final_locals) = &self.replacements.fragments[l] { for &(_, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageDead(fl)); } @@ -306,7 +280,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { return; } StatementKind::Deinit(box place) => { - if let Some(final_locals) = self.place_fragments(place) { + if let Some(final_locals) = self.replacements.place_fragments(place) { for &(_, fl) in final_locals { self.patch .add_statement(location, StatementKind::Deinit(Box::new(fl.into()))); @@ -317,7 +291,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } StatementKind::Assign(box (place, Rvalue::Aggregate(_, ref operands))) => { - if let Some(final_locals) = self.place_fragments(place) { + if let Some(final_locals) = self.replacements.place_fragments(place) { for &(projection, fl) in final_locals { let &[PlaceElem::Field(index, _)] = projection else { bug!() }; let index = index.as_usize(); @@ -333,7 +307,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } StatementKind::Assign(box (place, Rvalue::Use(Operand::Constant(_)))) => { - if let Some(final_locals) = self.place_fragments(place) { + if let Some(final_locals) = self.replacements.place_fragments(place) { for &(projection, fl) in final_locals { let rvalue = Rvalue::Use(Operand::Move(place.project_deeper(projection, self.tcx))); @@ -353,9 +327,12 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { Operand::Move(rplace) => (rplace, false), Operand::Constant(_) => bug!(), }; - if let Some(final_locals) = self.place_fragments(lhs) { + if let Some(final_locals) = self.replacements.place_fragments(lhs) { for &(projection, fl) in final_locals { let rplace = rplace.project_deeper(projection, self.tcx); + debug!(?rplace); + let rplace = self.replace_place(rplace.as_ref()).unwrap_or(rplace); + debug!(?rplace); let rvalue = if copy { Rvalue::Use(Operand::Copy(rplace)) } else { @@ -389,7 +366,9 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { VarDebugInfoContents::Place(ref mut place) => { if let Some(repl) = self.replace_place(place.as_ref()) { *place = repl; - } else if let Some(fragments) = self.gather_debug_info_fragments(place.as_ref()) { + } else if let Some(fragments) = + self.replacements.gather_debug_info_fragments(place.as_ref()) + { let ty = place.ty(self.local_decls, self.tcx).ty; var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; } @@ -401,8 +380,9 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { if let Some(repl) = self.replace_place(fragment.contents.as_ref()) { fragment.contents = repl; true - } else if let Some(frg) = - self.gather_debug_info_fragments(fragment.contents.as_ref()) + } else if let Some(frg) = self + .replacements + .gather_debug_info_fragments(fragment.contents.as_ref()) { new_fragments.extend(frg.into_iter().map(|mut f| { f.projection.splice(0..0, fragment.projection.iter().copied()); diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index e14e586f34b09..f1f53a481655c 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -8,8 +8,8 @@ let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:15: +4:16 let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:19: +4:20 let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:+4:23: +4:24 - let mut _13: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16 - let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22 + let mut _12: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:13: +13:16 + let mut _13: u32; // in scope 0 at $DIR/const_debuginfo.rs:+13:19: +13:22 scope 1 { - debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10 + debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:+1:9: +1:10 @@ -29,19 +29,21 @@ scope 5 { - debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10 + debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:+6:9: +6:10 - let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _14: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _15: bool; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _16: u32; // in scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 scope 6 { - debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10 - let _11: std::option::Option; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 + debug f => (bool, bool, u32){ .0 => _14, .1 => _15, .2 => _16, }; // in scope 6 at $DIR/const_debuginfo.rs:+8:9: +8:10 + let _10: std::option::Option; // in scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 scope 7 { - debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10 - let _15: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 - let _16: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + debug o => _10; // in scope 7 at $DIR/const_debuginfo.rs:+10:9: +10:10 + let _17: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _18: u32; // in scope 7 at $DIR/const_debuginfo.rs:+12:9: +12:10 scope 8 { - debug p => Point{ .0 => _15, .1 => _16, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 - let _12: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 + debug p => Point{ .0 => _17, .1 => _18, }; // in scope 8 at $DIR/const_debuginfo.rs:+12:9: +12:10 + let _11: u32; // in scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 scope 9 { -- debug a => _12; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 +- debug a => _11; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 + debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:+13:9: +13:10 } } @@ -67,17 +69,23 @@ // mir::Constant // + span: $DIR/const_debuginfo.rs:14:13: 14:28 // + literal: Const { ty: &str, val: Value(Slice(..)) } - StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 - _10 = (const true, const false, const 123_u32); // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 - StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 - _11 = Option::::Some(const 99_u16); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 - _15 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - _16 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 - StorageLive(_12); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 - _12 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22 - StorageDead(_12); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2 - StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageLive(_14); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + StorageLive(_15); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + StorageLive(_16); // scope 5 at $DIR/const_debuginfo.rs:+8:9: +8:10 + _14 = const true; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + _15 = const false; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + _16 = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:+8:13: +8:34 + StorageLive(_10); // scope 6 at $DIR/const_debuginfo.rs:+10:9: +10:10 + _10 = Option::::Some(const 99_u16); // scope 6 at $DIR/const_debuginfo.rs:+10:13: +10:24 + _17 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + _18 = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:+12:13: +12:35 + StorageLive(_11); // scope 8 at $DIR/const_debuginfo.rs:+13:9: +13:10 + _11 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:+13:13: +13:22 + StorageDead(_11); // scope 8 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_10); // scope 6 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_14); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_15); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 + StorageDead(_16); // scope 5 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:+14:1: +14:2 StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:+14:1: +14:2 return; // scope 0 at $DIR/const_debuginfo.rs:+14:2: +14:2 diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 0eb47087c9c75..37fbcf9dd496a 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -6,9 +6,10 @@ let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 scope 1 { debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 - let _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 + let _2: i32; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 + let _3: i32; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 scope 2 { - debug y => _2; // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 + debug y => (i32, i32){ .0 => _2, .1 => _3, }; // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 } } @@ -18,9 +19,13 @@ + _1 = const (42_i32, 43_i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+2:5: +2:13 StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 -- _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 -+ _2 = const (42_i32, 99_i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 + StorageLive(_3); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 +- _2 = (_1.0: i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 +- _3 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 ++ _2 = const 42_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 ++ _3 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 + StorageDead(_3); // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 return; // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:2: +4:2 } diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff index 26a1c3c1aa9e5..134f0c080bf81 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff @@ -9,9 +9,10 @@ let _2: &mut (i32, i32); // in scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10 scope 2 { debug z => _2; // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:9: +2:10 - let _3: (i32, i32); // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 + let _3: i32; // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 + let _4: i32; // in scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 scope 3 { - debug y => _3; // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 + debug y => (i32, i32){ .0 => _3, .1 => _4, }; // in scope 3 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 } } } @@ -23,8 +24,11 @@ _2 = &mut _1; // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+2:13: +2:19 ((*_2).1: i32) = const 99_i32; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+3:5: +3:13 StorageLive(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 - _3 = _1; // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14 + StorageLive(_4); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:9: +4:10 + _3 = (_1.0: i32); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14 + _4 = (_1.1: i32); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+4:13: +4:14 StorageDead(_3); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 + StorageDead(_4); // scope 2 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:1: +5:2 return; // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:+5:2: +5:2 diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 8bd589fb2c877..4010dd6c6d0d8 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -10,13 +10,13 @@ let mut _5: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 let mut _6: i32; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 scope 2 { - debug x => (i32, i32){ .1 => _5, .0 => _6, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + debug x => (i32, i32){ .0 => _5, .1 => _6, }; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 let _3: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 scope 3 { debug y => _3; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 let _4: i32; // in scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 scope 4 { - debug z => _6; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 + debug z => _5; // in scope 4 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 } } } @@ -31,17 +31,17 @@ } bb1: { - StorageLive(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 - _5 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 - _6 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + StorageLive(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:9: +2:14 + _5 = const 1_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 + _6 = const 2_i32; // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+2:29: +2:35 StorageLive(_2); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 _2 = _1; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 - _5 = move _2; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 + _6 = move _2; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:5: +3:12 StorageDead(_2); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+3:11: +3:12 StorageLive(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 - _3 = _5; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 + _3 = _6; // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 StorageDead(_3); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 - StorageDead(_5); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 + StorageDead(_6); // scope 1 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 StorageDead(_1); // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 return; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+6:2: +6:2 } diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff b/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff index 87271f24fc429..98cd020dade4b 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.diff @@ -11,6 +11,7 @@ let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -51,11 +52,14 @@ - _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -+ _10 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -+ _8 = _10; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 ++ _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 + StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 + nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 diff --git a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff index 72610de8eafa3..b76e2d6d0f294 100644 --- a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff @@ -5,44 +5,65 @@ debug x => _1; // in scope 0 at $DIR/sroa.rs:+0:11: +0:12 let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19 let _2: Foo; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 -+ let _5: u8; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 -+ let _6: &str; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 scope 1 { -- debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 -+ debug y => Foo{ .0 => _5, .2 => _6, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 + debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 let _3: u8; // in scope 1 at $DIR/sroa.rs:+2:9: +2:10 scope 2 { debug t => _3; // in scope 2 at $DIR/sroa.rs:+2:9: +2:10 let _4: &str; // in scope 2 at $DIR/sroa.rs:+3:9: +3:10 scope 3 { debug u => _4; // in scope 3 at $DIR/sroa.rs:+3:9: +3:10 + let _5: Foo; // in scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ let _7: u8; // in scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ let _8: (); // in scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ let _9: &str; // in scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ let _10: std::option::Option; // in scope 3 at $DIR/sroa.rs:+4:9: +4:10 + scope 4 { +- debug z => _5; // in scope 4 at $DIR/sroa.rs:+4:9: +4:10 ++ debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; // in scope 4 at $DIR/sroa.rs:+4:9: +4:10 + let _6: (); // in scope 4 at $DIR/sroa.rs:+5:9: +5:10 + scope 5 { + debug a => _6; // in scope 5 at $DIR/sroa.rs:+5:9: +5:10 + } + } } } } bb0: { -- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 -- _2 = _1; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 -+ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 -+ StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 -+ nop; // scope 0 at $DIR/sroa.rs:+1:9: +1:10 -+ _5 = (_1.0: u8); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 -+ _6 = (_1.2: &str); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 -+ nop; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 + StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 + _2 = _1; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 StorageLive(_3); // scope 1 at $DIR/sroa.rs:+2:9: +2:10 -- _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 -+ _3 = _5; // scope 1 at $DIR/sroa.rs:+2:13: +2:16 + _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 StorageLive(_4); // scope 2 at $DIR/sroa.rs:+3:9: +3:10 -- _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 -+ _4 = _6; // scope 2 at $DIR/sroa.rs:+3:13: +3:16 - _0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +4:2 - StorageDead(_4); // scope 2 at $DIR/sroa.rs:+4:1: +4:2 - StorageDead(_3); // scope 1 at $DIR/sroa.rs:+4:1: +4:2 -- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 -+ StorageDead(_5); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 -+ StorageDead(_6); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 -+ nop; // scope 0 at $DIR/sroa.rs:+4:1: +4:2 - return; // scope 0 at $DIR/sroa.rs:+4:2: +4:2 + _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 +- StorageLive(_5); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 +- _5 = _2; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ StorageLive(_7); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ StorageLive(_8); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ StorageLive(_9); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ StorageLive(_10); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ nop; // scope 3 at $DIR/sroa.rs:+4:9: +4:10 ++ _7 = (_2.0: u8); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _8 = (_2.1: ()); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _9 = (_2.2: &str); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _10 = (_2.3: std::option::Option); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ nop; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 + StorageLive(_6); // scope 4 at $DIR/sroa.rs:+5:9: +5:10 +- _6 = (_5.1: ()); // scope 4 at $DIR/sroa.rs:+5:13: +5:16 ++ _6 = _8; // scope 4 at $DIR/sroa.rs:+5:13: +5:16 + _0 = const (); // scope 0 at $DIR/sroa.rs:+0:19: +6:2 + StorageDead(_6); // scope 4 at $DIR/sroa.rs:+6:1: +6:2 +- StorageDead(_5); // scope 3 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_7); // scope 3 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_8); // scope 3 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_9); // scope 3 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_10); // scope 3 at $DIR/sroa.rs:+6:1: +6:2 ++ nop; // scope 3 at $DIR/sroa.rs:+6:1: +6:2 + StorageDead(_4); // scope 2 at $DIR/sroa.rs:+6:1: +6:2 + StorageDead(_3); // scope 1 at $DIR/sroa.rs:+6:1: +6:2 + StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 + return; // scope 0 at $DIR/sroa.rs:+6:2: +6:2 } } diff --git a/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff index 1a561a9edde30..f0d62220dd664 100644 --- a/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff @@ -6,10 +6,12 @@ let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:24: +0:24 let _2: Foo; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 + let _5: u8; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 -+ let _6: &str; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _6: (); // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _7: &str; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _8: std::option::Option; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 scope 1 { - debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 -+ debug y => Foo{ .0 => _5, .2 => _6, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 ++ debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 let _3: u8; // in scope 1 at $DIR/sroa.rs:+2:9: +2:10 scope 2 { debug t => _3; // in scope 2 at $DIR/sroa.rs:+2:9: +2:10 @@ -25,22 +27,28 @@ - _2 = (*_1); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 + StorageLive(_5); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 + StorageLive(_6); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_7); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_8); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 + nop; // scope 0 at $DIR/sroa.rs:+1:9: +1:10 + _5 = ((*_1).0: u8); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 -+ _6 = ((*_1).2: &str); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 ++ _6 = ((*_1).1: ()); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 ++ _7 = ((*_1).2: &str); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 ++ _8 = ((*_1).3: std::option::Option); // scope 0 at $DIR/sroa.rs:+1:13: +1:15 + nop; // scope 0 at $DIR/sroa.rs:+1:13: +1:15 StorageLive(_3); // scope 1 at $DIR/sroa.rs:+2:9: +2:10 - _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 + _3 = _5; // scope 1 at $DIR/sroa.rs:+2:13: +2:16 StorageLive(_4); // scope 2 at $DIR/sroa.rs:+3:9: +3:10 - _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 -+ _4 = _6; // scope 2 at $DIR/sroa.rs:+3:13: +3:16 ++ _4 = _7; // scope 2 at $DIR/sroa.rs:+3:13: +3:16 _0 = const (); // scope 0 at $DIR/sroa.rs:+0:24: +4:2 StorageDead(_4); // scope 2 at $DIR/sroa.rs:+4:1: +4:2 StorageDead(_3); // scope 1 at $DIR/sroa.rs:+4:1: +4:2 - StorageDead(_2); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 + StorageDead(_5); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 + StorageDead(_6); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ StorageDead(_7); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 ++ StorageDead(_8); // scope 0 at $DIR/sroa.rs:+4:1: +4:2 + nop; // scope 0 at $DIR/sroa.rs:+4:1: +4:2 return; // scope 0 at $DIR/sroa.rs:+4:2: +4:2 } diff --git a/tests/mir-opt/sroa.rs b/tests/mir-opt/sroa.rs index b80f61600c266..471aac9f9d82d 100644 --- a/tests/mir-opt/sroa.rs +++ b/tests/mir-opt/sroa.rs @@ -77,6 +77,8 @@ fn copies(x: Foo) { let y = x; let t = y.a; let u = y.c; + let z = y; + let a = z.b; } fn ref_copies(x: &Foo) { diff --git a/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff index ca3cb3d8ed139..2c63d8b266dde 100644 --- a/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff @@ -6,22 +6,26 @@ let mut _0: f32; // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:30 let mut _2: structs::U; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 let mut _3: f32; // in scope 0 at $DIR/sroa.rs:+6:18: +6:19 -+ let mut _4: f32; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ let mut _4: usize; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ let mut _5: f32; // in scope 0 at $DIR/sroa.rs:+6:5: +6:21 bb0: { - StorageLive(_2); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 + StorageLive(_4); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ StorageLive(_5); // scope 0 at $DIR/sroa.rs:+6:5: +6:21 + nop; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 StorageLive(_3); // scope 0 at $DIR/sroa.rs:+6:18: +6:19 _3 = _1; // scope 0 at $DIR/sroa.rs:+6:18: +6:19 - _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 -+ _4 = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ _4 = const 0_usize; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 ++ _5 = move _3; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 + nop; // scope 0 at $DIR/sroa.rs:+6:5: +6:21 StorageDead(_3); // scope 0 at $DIR/sroa.rs:+6:20: +6:21 - _0 = (_2.1: f32); // scope 0 at $DIR/sroa.rs:+6:5: +6:23 - StorageDead(_2); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 -+ _0 = _4; // scope 0 at $DIR/sroa.rs:+6:5: +6:23 ++ _0 = _5; // scope 0 at $DIR/sroa.rs:+6:5: +6:23 + StorageDead(_4); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 ++ StorageDead(_5); // scope 0 at $DIR/sroa.rs:+7:1: +7:2 + nop; // scope 0 at $DIR/sroa.rs:+7:1: +7:2 return; // scope 0 at $DIR/sroa.rs:+7:2: +7:2 } From 8e05ab04e54f2531198bb61c32ad2232d682a63c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Feb 2023 12:08:42 +0000 Subject: [PATCH 5/7] Run SROA to fixpoint. --- .../rustc_mir_dataflow/src/value_analysis.rs | 2 +- compiler/rustc_mir_transform/src/sroa.rs | 74 +++++++++---------- ...ble_variable_aggregate.main.ConstProp.diff | 27 +++---- ....copies.ScalarReplacementOfAggregates.diff | 42 ++++++++--- 4 files changed, 78 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 90d07c81256f5..8bf6493be4b01 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -824,7 +824,7 @@ pub fn iter_fields<'tcx>( } /// Returns all locals with projections that have their reference or address taken. -fn excluded_locals(body: &Body<'_>) -> IndexVec { +pub fn excluded_locals(body: &Body<'_>) -> IndexVec { struct Collector { result: IndexVec, } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 3cfa0b16499a6..28963c77aa55f 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use rustc_mir_dataflow::value_analysis::iter_fields; +use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields}; pub struct ScalarReplacementOfAggregates; @@ -18,26 +18,38 @@ impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates { #[instrument(level = "debug", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - let escaping = escaping_locals(&*body); - debug!(?escaping); - let replacements = compute_flattening(tcx, body, escaping); - debug!(?replacements); - replace_flattened_locals(tcx, body, replacements); + let mut excluded = excluded_locals(body); + loop { + debug!(?excluded); + let escaping = escaping_locals(&excluded, body); + debug!(?escaping); + let replacements = compute_flattening(tcx, body, escaping); + debug!(?replacements); + let all_dead_locals = replace_flattened_locals(tcx, body, replacements); + if !all_dead_locals.is_empty() && tcx.sess.mir_opt_level() >= 4 { + for local in excluded.indices() { + excluded[local] |= all_dead_locals.contains(local) ; + } + excluded.raw.resize(body.local_decls.len(), false); + } else { + break + } + } } } /// Identify all locals that are not eligible for SROA. /// /// There are 3 cases: -/// - the aggegated local is used or passed to other code (function parameters and arguments); +/// - the aggregated local is used or passed to other code (function parameters and arguments); /// - the locals is a union or an enum; /// - the local's address is taken, and thus the relative addresses of the fields are observable to /// client code. -fn escaping_locals(body: &Body<'_>) -> BitSet { +fn escaping_locals(excluded: &IndexVec, body: &Body<'_>) -> BitSet { let mut set = BitSet::new_empty(body.local_decls.len()); set.insert_range(RETURN_PLACE..=Local::from_usize(body.arg_count)); for (local, decl) in body.local_decls().iter_enumerated() { - if decl.ty.is_union() || decl.ty.is_enum() { + if decl.ty.is_union() || decl.ty.is_enum() || excluded[local] { set.insert(local); } } @@ -62,17 +74,6 @@ fn escaping_locals(body: &Body<'_>) -> BitSet { self.super_place(place, context, location); } - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::AddressOf(.., place) | Rvalue::Ref(.., place) = rvalue { - if !place.is_indirect() { - // Raw pointers may be used to access anything inside the enclosing place. - self.set.insert(place.local); - return; - } - } - self.super_rvalue(rvalue, location) - } - fn visit_assign( &mut self, lvalue: &Place<'tcx>, @@ -102,21 +103,6 @@ fn escaping_locals(body: &Body<'_>) -> BitSet { } } - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - // Drop implicitly calls `drop_in_place`, which takes a `&mut`. - // This implies that `Drop` implicitly takes the address of the place. - if let TerminatorKind::Drop { place, .. } - | TerminatorKind::DropAndReplace { place, .. } = terminator.kind - { - if !place.is_indirect() { - // Raw pointers may be used to access anything inside the enclosing place. - self.set.insert(place.local); - return; - } - } - self.super_terminator(terminator, location); - } - // We ignore anything that happens in debuginfo, since we expand it using // `VarDebugInfoContents::Composite`. fn visit_var_debug_info(&mut self, _: &VarDebugInfo<'tcx>) {} @@ -198,14 +184,14 @@ fn replace_flattened_locals<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, replacements: ReplacementMap<'tcx>, -) { +) -> BitSet { let mut all_dead_locals = BitSet::new_empty(body.local_decls.len()); for p in replacements.fields.keys() { all_dead_locals.insert(p.local); } debug!(?all_dead_locals); if all_dead_locals.is_empty() { - return; + return all_dead_locals; } let mut visitor = ReplacementVisitor { @@ -227,7 +213,9 @@ fn replace_flattened_locals<'tcx>( for var_debug_info in &mut body.var_debug_info { visitor.visit_var_debug_info(var_debug_info); } - visitor.patch.apply(body); + let ReplacementVisitor { patch, all_dead_locals, .. } = visitor; + patch.apply(body); + all_dead_locals } struct ReplacementVisitor<'tcx, 'll> { @@ -361,6 +349,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } } + #[instrument(level = "trace", skip(self))] fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { match &mut var_debug_info.value { VarDebugInfoContents::Place(ref mut place) => { @@ -375,11 +364,12 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } VarDebugInfoContents::Composite { ty: _, ref mut fragments } => { let mut new_fragments = Vec::new(); + debug!(?fragments); fragments .drain_filter(|fragment| { if let Some(repl) = self.replace_place(fragment.contents.as_ref()) { fragment.contents = repl; - true + false } else if let Some(frg) = self .replacements .gather_debug_info_fragments(fragment.contents.as_ref()) @@ -388,12 +378,14 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { f.projection.splice(0..0, fragment.projection.iter().copied()); f })); - false - } else { true + } else { + false } }) .for_each(drop); + debug!(?fragments); + debug!(?new_fragments); fragments.extend(new_fragments); } VarDebugInfoContents::Const(_) => {} diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 37fbcf9dd496a..d088c4f662b7b 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -3,30 +3,27 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate.rs:+0:11: +0:11 - let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 + let mut _3: i32; // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 + let mut _4: i32; // in scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 scope 1 { - debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 + debug x => (i32, i32){ .0 => _3, .1 => _4, }; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 + let _1: i32; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 let _2: i32; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 - let _3: i32; // in scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 scope 2 { - debug y => (i32, i32){ .0 => _2, .1 => _3, }; // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 + debug y => (i32, i32){ .0 => _3, .1 => _2, }; // in scope 2 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 -- _1 = (const 42_i32, const 43_i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 -+ _1 = const (42_i32, 43_i32); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 - (_1.1: i32) = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+2:5: +2:13 + StorageLive(_4); // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:9: +1:14 + _3 = const 42_i32; // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 + _4 = const 43_i32; // scope 0 at $DIR/mutable_variable_aggregate.rs:+1:17: +1:25 + _4 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+2:5: +2:13 StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 - StorageLive(_3); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:9: +3:10 -- _2 = (_1.0: i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 -- _3 = (_1.1: i32); // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 -+ _2 = const 42_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 -+ _3 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 +- _2 = _4; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 ++ _2 = const 99_i32; // scope 1 at $DIR/mutable_variable_aggregate.rs:+3:13: +3:14 StorageDead(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 - StorageDead(_3); // scope 1 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 - StorageDead(_1); // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 + StorageDead(_4); // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:1: +4:2 return; // scope 0 at $DIR/mutable_variable_aggregate.rs:+4:2: +4:2 } } diff --git a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff index b76e2d6d0f294..976f6d44b7521 100644 --- a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff @@ -5,8 +5,13 @@ debug x => _1; // in scope 0 at $DIR/sroa.rs:+0:11: +0:12 let mut _0: (); // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19 let _2: Foo; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _11: u8; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _12: (); // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _13: &str; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ let _14: std::option::Option; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10 scope 1 { - debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 +- debug y => _2; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 ++ debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10 let _3: u8; // in scope 1 at $DIR/sroa.rs:+2:9: +2:10 scope 2 { debug t => _3; // in scope 2 at $DIR/sroa.rs:+2:9: +2:10 @@ -31,23 +36,35 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 - _2 = _1; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 +- StorageLive(_2); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 +- _2 = _1; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ StorageLive(_11); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_12); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_13); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ StorageLive(_14); // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ nop; // scope 0 at $DIR/sroa.rs:+1:9: +1:10 ++ _11 = (_1.0: u8); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ _12 = (_1.1: ()); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ _13 = (_1.2: &str); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ _14 = (_1.3: std::option::Option); // scope 0 at $DIR/sroa.rs:+1:13: +1:14 ++ nop; // scope 0 at $DIR/sroa.rs:+1:13: +1:14 StorageLive(_3); // scope 1 at $DIR/sroa.rs:+2:9: +2:10 - _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 +- _3 = (_2.0: u8); // scope 1 at $DIR/sroa.rs:+2:13: +2:16 ++ _3 = _11; // scope 1 at $DIR/sroa.rs:+2:13: +2:16 StorageLive(_4); // scope 2 at $DIR/sroa.rs:+3:9: +3:10 - _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 +- _4 = (_2.2: &str); // scope 2 at $DIR/sroa.rs:+3:13: +3:16 - StorageLive(_5); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 - _5 = _2; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _4 = _13; // scope 2 at $DIR/sroa.rs:+3:13: +3:16 + StorageLive(_7); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 + StorageLive(_8); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 + StorageLive(_9); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 + StorageLive(_10); // scope 3 at $DIR/sroa.rs:+4:9: +4:10 + nop; // scope 3 at $DIR/sroa.rs:+4:9: +4:10 -+ _7 = (_2.0: u8); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 -+ _8 = (_2.1: ()); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 -+ _9 = (_2.2: &str); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 -+ _10 = (_2.3: std::option::Option); // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _7 = _11; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _8 = _12; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _9 = _13; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 ++ _10 = _14; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 + nop; // scope 3 at $DIR/sroa.rs:+4:13: +4:14 StorageLive(_6); // scope 4 at $DIR/sroa.rs:+5:9: +5:10 - _6 = (_5.1: ()); // scope 4 at $DIR/sroa.rs:+5:13: +5:16 @@ -62,7 +79,12 @@ + nop; // scope 3 at $DIR/sroa.rs:+6:1: +6:2 StorageDead(_4); // scope 2 at $DIR/sroa.rs:+6:1: +6:2 StorageDead(_3); // scope 1 at $DIR/sroa.rs:+6:1: +6:2 - StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 +- StorageDead(_2); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_11); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_12); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_13); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 ++ StorageDead(_14); // scope 0 at $DIR/sroa.rs:+6:1: +6:2 ++ nop; // scope 0 at $DIR/sroa.rs:+6:1: +6:2 return; // scope 0 at $DIR/sroa.rs:+6:2: +6:2 } } From 29856180a8ba8e0d217d2df1bd4e8de0efe293f7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Feb 2023 13:35:33 +0000 Subject: [PATCH 6/7] Simplify ReplacementMap. --- compiler/rustc_mir_transform/src/sroa.rs | 193 +++++++++++++---------- 1 file changed, 109 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 28963c77aa55f..26acd406ed8a9 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,11 +1,10 @@ use crate::MirPass; -use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields}; pub struct ScalarReplacementOfAggregates; @@ -26,13 +25,13 @@ impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates { let replacements = compute_flattening(tcx, body, escaping); debug!(?replacements); let all_dead_locals = replace_flattened_locals(tcx, body, replacements); - if !all_dead_locals.is_empty() && tcx.sess.mir_opt_level() >= 4 { + if !all_dead_locals.is_empty() { for local in excluded.indices() { - excluded[local] |= all_dead_locals.contains(local) ; + excluded[local] |= all_dead_locals.contains(local); } excluded.raw.resize(body.local_decls.len(), false); } else { - break + break; } } } @@ -111,36 +110,29 @@ fn escaping_locals(excluded: &IndexVec, body: &Body<'_>) -> BitSet< #[derive(Default, Debug)] struct ReplacementMap<'tcx> { - fields: FxIndexMap, Local>, /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage /// and deinit statement and debuginfo. - fragments: IndexVec], Local)>>>, + fragments: IndexVec, Local)>>>>, } impl<'tcx> ReplacementMap<'tcx> { - fn gather_debug_info_fragments( - &self, - place: PlaceRef<'tcx>, - ) -> Option>> { - let mut fragments = Vec::new(); - let Some(parts) = &self.fragments[place.local] else { return None }; - for (proj, replacement_local) in parts { - if proj.starts_with(place.projection) { - fragments.push(VarDebugInfoFragment { - projection: proj[place.projection.len()..].to_vec(), - contents: Place::from(*replacement_local), - }); - } - } - Some(fragments) + fn replace_place(&self, tcx: TyCtxt<'tcx>, place: PlaceRef<'tcx>) -> Option> { + let &[PlaceElem::Field(f, _), ref rest @ ..] = place.projection else { return None; }; + let fields = self.fragments[place.local].as_ref()?; + let (_, new_local) = fields[f]?; + Some(Place { local: new_local, projection: tcx.intern_place_elems(&rest) }) } fn place_fragments( &self, place: Place<'tcx>, - ) -> Option<&Vec<(&'tcx [PlaceElem<'tcx>], Local)>> { + ) -> Option, Local)> + '_> { let local = place.as_local()?; - self.fragments[local].as_ref() + let fields = self.fragments[local].as_ref()?; + Some(fields.iter_enumerated().filter_map(|(field, &opt_ty_local)| { + let (ty, local) = opt_ty_local?; + Some((field, ty, local)) + })) } } @@ -153,8 +145,7 @@ fn compute_flattening<'tcx>( body: &mut Body<'tcx>, escaping: BitSet, ) -> ReplacementMap<'tcx> { - let mut fields = FxIndexMap::default(); - let mut fragments = IndexVec::from_elem(None::>, &body.local_decls); + let mut fragments = IndexVec::from_elem(None, &body.local_decls); for local in body.local_decls.indices() { if escaping.contains(local) { @@ -169,14 +160,10 @@ fn compute_flattening<'tcx>( }; let new_local = body.local_decls.push(LocalDecl { ty: field_ty, user_ty: None, ..decl.clone() }); - let place = Place::from(local) - .project_deeper(&[PlaceElem::Field(field, field_ty)], tcx) - .as_ref(); - fields.insert(place, new_local); - fragments[local].get_or_insert_default().push((place.projection, new_local)); + fragments.get_or_insert_with(local, IndexVec::new).insert(field, (field_ty, new_local)); }); } - ReplacementMap { fields, fragments } + ReplacementMap { fragments } } /// Perform the replacement computed by `compute_flattening`. @@ -186,8 +173,10 @@ fn replace_flattened_locals<'tcx>( replacements: ReplacementMap<'tcx>, ) -> BitSet { let mut all_dead_locals = BitSet::new_empty(body.local_decls.len()); - for p in replacements.fields.keys() { - all_dead_locals.insert(p.local); + for (local, replacements) in replacements.fragments.iter_enumerated() { + if replacements.is_some() { + all_dead_locals.insert(local); + } } debug!(?all_dead_locals); if all_dead_locals.is_empty() { @@ -197,7 +186,7 @@ fn replace_flattened_locals<'tcx>( let mut visitor = ReplacementVisitor { tcx, local_decls: &body.local_decls, - replacements, + replacements: &replacements, all_dead_locals, patch: MirPatch::new(body), }; @@ -223,21 +212,23 @@ struct ReplacementVisitor<'tcx, 'll> { /// This is only used to compute the type for `VarDebugInfoContents::Composite`. local_decls: &'ll LocalDecls<'tcx>, /// Work to do. - replacements: ReplacementMap<'tcx>, + replacements: &'ll ReplacementMap<'tcx>, /// This is used to check that we are not leaving references to replaced locals behind. all_dead_locals: BitSet, patch: MirPatch<'tcx>, } -impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> { - fn replace_place(&self, place: PlaceRef<'tcx>) -> Option> { - if let &[PlaceElem::Field(..), ref rest @ ..] = place.projection { - let pr = PlaceRef { local: place.local, projection: &place.projection[..1] }; - let local = self.replacements.fields.get(&pr)?; - Some(Place { local: *local, projection: self.tcx.intern_place_elems(&rest) }) - } else { - None +impl<'tcx> ReplacementVisitor<'tcx, '_> { + fn gather_debug_info_fragments(&self, local: Local) -> Option>> { + let mut fragments = Vec::new(); + let parts = self.replacements.place_fragments(local.into())?; + for (field, ty, replacement_local) in parts { + fragments.push(VarDebugInfoFragment { + projection: vec![PlaceElem::Field(field, ty)], + contents: Place::from(replacement_local), + }); } + Some(fragments) } } @@ -246,12 +237,21 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.tcx } + fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { + *place = repl + } else { + self.super_place(place, context, location) + } + } + #[instrument(level = "trace", skip(self))] fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { match statement.kind { + // Duplicate storage and deinit statements, as they pretty much apply to all fields. StatementKind::StorageLive(l) => { - if let Some(final_locals) = &self.replacements.fragments[l] { - for &(_, fl) in final_locals { + if let Some(final_locals) = self.replacements.place_fragments(l.into()) { + for (_, _, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageLive(fl)); } statement.make_nop(); @@ -259,8 +259,8 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { return; } StatementKind::StorageDead(l) => { - if let Some(final_locals) = &self.replacements.fragments[l] { - for &(_, fl) in final_locals { + if let Some(final_locals) = self.replacements.place_fragments(l.into()) { + for (_, _, fl) in final_locals { self.patch.add_statement(location, StatementKind::StorageDead(fl)); } statement.make_nop(); @@ -269,7 +269,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } StatementKind::Deinit(box place) => { if let Some(final_locals) = self.replacements.place_fragments(place) { - for &(_, fl) in final_locals { + for (_, _, fl) in final_locals { self.patch .add_statement(location, StatementKind::Deinit(Box::new(fl.into()))); } @@ -278,48 +278,80 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { } } - StatementKind::Assign(box (place, Rvalue::Aggregate(_, ref operands))) => { - if let Some(final_locals) = self.replacements.place_fragments(place) { - for &(projection, fl) in final_locals { - let &[PlaceElem::Field(index, _)] = projection else { bug!() }; - let index = index.as_usize(); - let rvalue = Rvalue::Use(operands[index].clone()); - self.patch.add_statement( - location, - StatementKind::Assign(Box::new((fl.into(), rvalue))), - ); + // We have `a = Struct { 0: x, 1: y, .. }`. + // We replace it by + // ``` + // a_0 = x + // a_1 = y + // ... + // ``` + StatementKind::Assign(box (place, Rvalue::Aggregate(_, ref mut operands))) => { + if let Some(local) = place.as_local() + && let Some(final_locals) = &self.replacements.fragments[local] + { + // This is ok as we delete the statement later. + let operands = std::mem::take(operands); + for (&opt_ty_local, mut operand) in final_locals.iter().zip(operands) { + if let Some((_, new_local)) = opt_ty_local { + // Replace mentions of SROA'd locals that appear in the operand. + self.visit_operand(&mut operand, location); + + let rvalue = Rvalue::Use(operand); + self.patch.add_statement( + location, + StatementKind::Assign(Box::new((new_local.into(), rvalue))), + ); + } } statement.make_nop(); return; } } + // We have `a = some constant` + // We add the projections. + // ``` + // a_0 = a.0 + // a_1 = a.1 + // ... + // ``` + // ConstProp will pick up the pieces and replace them by actual constants. StatementKind::Assign(box (place, Rvalue::Use(Operand::Constant(_)))) => { if let Some(final_locals) = self.replacements.place_fragments(place) { - for &(projection, fl) in final_locals { - let rvalue = - Rvalue::Use(Operand::Move(place.project_deeper(projection, self.tcx))); + for (field, ty, new_local) in final_locals { + let rplace = self.tcx.mk_place_field(place, field, ty); + let rvalue = Rvalue::Use(Operand::Move(rplace)); self.patch.add_statement( location, - StatementKind::Assign(Box::new((fl.into(), rvalue))), + StatementKind::Assign(Box::new((new_local.into(), rvalue))), ); } - self.all_dead_locals.remove(place.local); + // We still need `place.local` to exist, so don't make it nop. return; } } + // We have `a = move? place` + // We replace it by + // ``` + // a_0 = move? place.0 + // a_1 = move? place.1 + // ... + // ``` StatementKind::Assign(box (lhs, Rvalue::Use(ref op))) => { - let (rplace, copy) = match op { + let (rplace, copy) = match *op { Operand::Copy(rplace) => (rplace, true), Operand::Move(rplace) => (rplace, false), Operand::Constant(_) => bug!(), }; if let Some(final_locals) = self.replacements.place_fragments(lhs) { - for &(projection, fl) in final_locals { - let rplace = rplace.project_deeper(projection, self.tcx); + for (field, ty, new_local) in final_locals { + let rplace = self.tcx.mk_place_field(rplace, field, ty); debug!(?rplace); - let rplace = self.replace_place(rplace.as_ref()).unwrap_or(rplace); + let rplace = self + .replacements + .replace_place(self.tcx, rplace.as_ref()) + .unwrap_or(rplace); debug!(?rplace); let rvalue = if copy { Rvalue::Use(Operand::Copy(rplace)) @@ -328,7 +360,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { }; self.patch.add_statement( location, - StatementKind::Assign(Box::new((fl.into(), rvalue))), + StatementKind::Assign(Box::new((new_local.into(), rvalue))), ); } statement.make_nop(); @@ -341,22 +373,14 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { self.super_statement(statement, location) } - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if let Some(repl) = self.replace_place(place.as_ref()) { - *place = repl - } else { - self.super_place(place, context, location) - } - } - #[instrument(level = "trace", skip(self))] fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { match &mut var_debug_info.value { VarDebugInfoContents::Place(ref mut place) => { - if let Some(repl) = self.replace_place(place.as_ref()) { + if let Some(repl) = self.replacements.replace_place(self.tcx, place.as_ref()) { *place = repl; - } else if let Some(fragments) = - self.replacements.gather_debug_info_fragments(place.as_ref()) + } else if let Some(local) = place.as_local() + && let Some(fragments) = self.gather_debug_info_fragments(local) { let ty = place.ty(self.local_decls, self.tcx).ty; var_debug_info.value = VarDebugInfoContents::Composite { ty, fragments }; @@ -367,12 +391,13 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { debug!(?fragments); fragments .drain_filter(|fragment| { - if let Some(repl) = self.replace_place(fragment.contents.as_ref()) { + if let Some(repl) = + self.replacements.replace_place(self.tcx, fragment.contents.as_ref()) + { fragment.contents = repl; false - } else if let Some(frg) = self - .replacements - .gather_debug_info_fragments(fragment.contents.as_ref()) + } else if let Some(local) = fragment.contents.as_local() + && let Some(frg) = self.gather_debug_info_fragments(local) { new_fragments.extend(frg.into_iter().map(|mut f| { f.projection.splice(0..0, fragment.projection.iter().copied()); From 51ef82d19ba97fd60d13d02f708fd0eb43617cc7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Feb 2023 13:51:37 +0000 Subject: [PATCH 7/7] Bless 32bit tests. --- ...es_into_variable.main.ConstProp.32bit.diff | 12 +++-------- ...o_variable.main.PreCodegen.after.32bit.mir | 4 +--- ...n.ScalarReplacementOfAggregates.32bit.diff | 20 +++++++++++++++---- ....main.SimplifyLocals-final.after.32bit.mir | 4 +--- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 1368b114658df..691aa01a56408 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -9,7 +9,7 @@ let _5: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:32: +2:33 let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 - let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 + let mut _9: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -17,7 +17,7 @@ debug y => _3; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 let _8: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 scope 3 { - debug z => _8; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 + debug z => _9; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 } } } @@ -50,13 +50,7 @@ + _3 = const 3_i32; // scope 1 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 - StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 -- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 -+ _8 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 - StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 + _9 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir b/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir index 9db87cfc879bb..81cfd22db6c50 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.PreCodegen.after.32bit.mir @@ -3,12 +3,12 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _3: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 scope 2 { debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 scope 3 { debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 } @@ -18,8 +18,6 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2 diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff b/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff index de1d57ed401a1..98cd020dade4b 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.diff @@ -10,6 +10,8 @@ let mut _6: usize; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _7: bool; // in scope 0 at $DIR/optimizes_into_variable.rs:+2:13: +2:34 let mut _9: Point; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _10: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ let mut _11: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _3: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 @@ -45,10 +47,20 @@ StorageDead(_5); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageDead(_4); // scope 1 at $DIR/optimizes_into_variable.rs:+2:34: +2:35 StorageLive(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 - _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 - StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 +- StorageLive(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _9 = Point { x: const 12_u32, y: const 42_u32 }; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 +- _8 = (_9.1: u32); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 +- StorageDead(_9); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageLive(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ StorageLive(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _10 = const 12_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _11 = const 42_u32; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 ++ _8 = _11; // scope 2 at $DIR/optimizes_into_variable.rs:+3:13: +3:38 ++ StorageDead(_10); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ StorageDead(_11); // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 ++ nop; // scope 2 at $DIR/optimizes_into_variable.rs:+3:38: +3:39 nop; // scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +4:2 StorageDead(_8); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_3); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 diff --git a/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir b/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir index d926b9df73317..002e914e8fa16 100644 --- a/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir +++ b/tests/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals-final.after.32bit.mir @@ -3,12 +3,12 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:+0:11: +0:11 let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 + let mut _3: u32; // in scope 0 at $DIR/optimizes_into_variable.rs:+3:13: +3:36 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 scope 2 { debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 scope 3 { debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 } @@ -18,8 +18,6 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+1:9: +1:10 StorageLive(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+2:9: +2:10 - StorageLive(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+3:9: +3:10 - StorageDead(_3); // scope 2 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_2); // scope 1 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 StorageDead(_1); // scope 0 at $DIR/optimizes_into_variable.rs:+4:1: +4:2 return; // scope 0 at $DIR/optimizes_into_variable.rs:+4:2: +4:2