From 2e034dc68cb4d593f564f5ff8c444be5d12fc95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Christopher=20K=C3=B6hl?= Date: Sat, 12 Nov 2022 14:57:14 +0100 Subject: [PATCH] Exclude locals completely, instead of individual places --- .../rustc_mir_dataflow/src/value_analysis.rs | 47 ++++++---------- .../sibling_ptr.main.DataflowConstProp.diff | 56 +++++++++++++++++++ .../dataflow-const-prop/sibling_ptr.rs | 11 ++++ 3 files changed, 85 insertions(+), 29 deletions(-) create mode 100644 src/test/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff create mode 100644 src/test/mir-opt/dataflow-const-prop/sibling_ptr.rs diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 0f3b952ceec8..85a35c13fd93 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -34,7 +34,7 @@ use std::fmt::{Debug, Formatter}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -587,7 +587,8 @@ impl Map { filter: impl FnMut(Ty<'tcx>) -> bool, ) -> Self { let mut map = Self::new(); - map.register_with_filter(tcx, body, filter, &escaped_places(body)); + let exclude = excluded_locals(body); + map.register_with_filter(tcx, body, filter, &exclude); debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len()); map } @@ -598,19 +599,14 @@ impl Map { tcx: TyCtxt<'tcx>, body: &Body<'tcx>, mut filter: impl FnMut(Ty<'tcx>) -> bool, - exclude: &FxHashSet>, + exclude: &IndexVec, ) { // We use this vector as stack, pushing and popping projections. let mut projection = Vec::new(); for (local, decl) in body.local_decls.iter_enumerated() { - self.register_with_filter_rec( - tcx, - local, - &mut projection, - decl.ty, - &mut filter, - exclude, - ); + if !exclude[local] { + self.register_with_filter_rec(tcx, local, &mut projection, decl.ty, &mut filter); + } } } @@ -624,17 +620,10 @@ impl Map { projection: &mut Vec>, ty: Ty<'tcx>, filter: &mut impl FnMut(Ty<'tcx>) -> bool, - exclude: &FxHashSet>, ) { - let place = Place { local, projection: tcx.intern_place_elems(projection) }; - if exclude.contains(&place) { - // This will also exclude all projections of the excluded place. - return; - } - // Note: The framework supports only scalars for now. if filter(ty) && ty.is_scalar() { - trace!("registering place: {:?}", place); + // trace!("registering place {:?}", PlaceRef { local, projection: &*projection }); // We know that the projection only contains trackable elements. let place = self.make_place(local, projection).unwrap(); @@ -653,7 +642,7 @@ impl Map { return; } projection.push(PlaceElem::Field(field, ty)); - self.register_with_filter_rec(tcx, local, projection, ty, filter, exclude); + self.register_with_filter_rec(tcx, local, projection, ty, filter); projection.pop(); }); } @@ -835,27 +824,27 @@ fn iter_fields<'tcx>( } } -/// Returns all places, that have their reference or address taken. -/// -/// This includes shared references, and also drops and `InlineAsm` out parameters. -fn escaped_places<'tcx>(body: &Body<'tcx>) -> FxHashSet> { - struct Collector<'tcx> { - result: FxHashSet>, +/// Returns all locals with projections that have their reference or address taken. +fn excluded_locals<'tcx>(body: &Body<'tcx>) -> IndexVec { + struct Collector { + result: IndexVec, } - impl<'tcx> Visitor<'tcx> for Collector<'tcx> { + impl<'tcx> Visitor<'tcx> for Collector { fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { if context.is_borrow() || context.is_address_of() || context.is_drop() || context == PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) { - self.result.insert(*place); + // A pointer to a place could be used to access other places with the same local, + // hence we have to exclude the local completely. + self.result[place.local] = true; } } } - let mut collector = Collector { result: FxHashSet::default() }; + let mut collector = Collector { result: IndexVec::from_elem(false, &body.local_decls) }; collector.visit_body(body); collector.result } diff --git a/src/test/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff b/src/test/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff new file mode 100644 index 000000000000..8126d4b8585e --- /dev/null +++ b/src/test/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.diff @@ -0,0 +1,56 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/sibling_ptr.rs:+0:11: +0:11 + let mut _1: (u8, u8); // in scope 0 at $DIR/sibling_ptr.rs:+1:9: +1:14 + let _2: (); // in scope 0 at $DIR/sibling_ptr.rs:+2:5: +5:6 + let mut _4: *mut u8; // in scope 0 at $DIR/sibling_ptr.rs:+4:10: +4:18 + let mut _5: *mut u8; // in scope 0 at $DIR/sibling_ptr.rs:+4:10: +4:11 + scope 1 { + debug x => _1; // in scope 1 at $DIR/sibling_ptr.rs:+1:9: +1:14 + let _6: u8; // in scope 1 at $DIR/sibling_ptr.rs:+6:9: +6:11 + scope 2 { + let _3: *mut u8; // in scope 2 at $DIR/sibling_ptr.rs:+3:13: +3:14 + scope 3 { + debug p => _3; // in scope 3 at $DIR/sibling_ptr.rs:+3:13: +3:14 + } + } + scope 4 { + debug x1 => _6; // in scope 4 at $DIR/sibling_ptr.rs:+6:9: +6:11 + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/sibling_ptr.rs:+1:9: +1:14 + Deinit(_1); // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33 + (_1.0: u8) = const 0_u8; // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33 + (_1.1: u8) = const 0_u8; // scope 0 at $DIR/sibling_ptr.rs:+1:27: +1:33 + StorageLive(_2); // scope 1 at $DIR/sibling_ptr.rs:+2:5: +5:6 + StorageLive(_3); // scope 2 at $DIR/sibling_ptr.rs:+3:13: +3:14 + _3 = &raw mut (_1.0: u8); // scope 2 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageLive(_4); // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:18 + StorageLive(_5); // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:11 + _5 = _3; // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:11 + _4 = ptr::mut_ptr::::add(move _5, const 1_usize) -> bb1; // scope 3 at $DIR/sibling_ptr.rs:+4:10: +4:18 + // mir::Constant + // + span: $DIR/sibling_ptr.rs:8:12: 8:15 + // + literal: Const { ty: unsafe fn(*mut u8, usize) -> *mut u8 {ptr::mut_ptr::::add}, val: Value() } + } + + bb1: { + StorageDead(_5); // scope 3 at $DIR/sibling_ptr.rs:+4:17: +4:18 + (*_4) = const 1_u8; // scope 3 at $DIR/sibling_ptr.rs:+4:9: +4:22 + StorageDead(_4); // scope 3 at $DIR/sibling_ptr.rs:+4:22: +4:23 + _2 = const (); // scope 2 at $DIR/sibling_ptr.rs:+2:5: +5:6 + StorageDead(_3); // scope 2 at $DIR/sibling_ptr.rs:+5:5: +5:6 + StorageDead(_2); // scope 1 at $DIR/sibling_ptr.rs:+5:5: +5:6 + StorageLive(_6); // scope 1 at $DIR/sibling_ptr.rs:+6:9: +6:11 + _6 = (_1.1: u8); // scope 1 at $DIR/sibling_ptr.rs:+6:14: +6:17 + _0 = const (); // scope 0 at $DIR/sibling_ptr.rs:+0:11: +7:2 + StorageDead(_6); // scope 1 at $DIR/sibling_ptr.rs:+7:1: +7:2 + StorageDead(_1); // scope 0 at $DIR/sibling_ptr.rs:+7:1: +7:2 + return; // scope 0 at $DIR/sibling_ptr.rs:+7:2: +7:2 + } + } + diff --git a/src/test/mir-opt/dataflow-const-prop/sibling_ptr.rs b/src/test/mir-opt/dataflow-const-prop/sibling_ptr.rs new file mode 100644 index 000000000000..87ef00d18295 --- /dev/null +++ b/src/test/mir-opt/dataflow-const-prop/sibling_ptr.rs @@ -0,0 +1,11 @@ +// unit-test: DataflowConstProp + +// EMIT_MIR sibling_ptr.main.DataflowConstProp.diff +fn main() { + let mut x: (u8, u8) = (0, 0); + unsafe { + let p = std::ptr::addr_of_mut!(x.0); + *p.add(1) = 1; + } + let x1 = x.1; // should not be propagated +}