diff options
| author | bors <bors@rust-lang.org> | 2025-08-23 05:07:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-08-23 05:07:11 +0000 |
| commit | 8df154bffddcb6bbb543ad69aff971795c5adbc2 (patch) | |
| tree | fb7a190550397be91be94378598f5154cebbdba6 /compiler/rustc_mir_transform | |
| parent | 78b89ebb6b20cf50370335e14c5357a4388ac760 (diff) | |
| parent | 418bbb283fca5e7ee5ebe30646a4dd7ae62698ea (diff) | |
| download | rust-8df154bffddcb6bbb543ad69aff971795c5adbc2.tar.gz rust-8df154bffddcb6bbb543ad69aff971795c5adbc2.zip | |
Auto merge of #145773 - jhpratt:rollup-kocqnzv, r=jhpratt
Rollup of 28 pull requests Successful merges: - rust-lang/rust#132087 (Fix overly restrictive lifetime in `core::panic::Location::file` return type) - rust-lang/rust#137396 (Recover `param: Ty = EXPR`) - rust-lang/rust#137457 (Fix host code appearing in Wasm binaries) - rust-lang/rust#142185 (Convert moves of references to copies in ReferencePropagation) - rust-lang/rust#144648 (Implementation: `#[feature(nonpoison_rwlock)]`) - rust-lang/rust#144897 (print raw lifetime idents with r#) - rust-lang/rust#145218 ([Debuginfo] improve enum value formatting in LLDB for better readability) - rust-lang/rust#145380 (Add codegen-llvm regression tests) - rust-lang/rust#145573 (Add an experimental unsafe(force_target_feature) attribute.) - rust-lang/rust#145597 (resolve: Remove `ScopeSet::Late`) - rust-lang/rust#145633 (Fix some typos in LocalKey documentation) - rust-lang/rust#145641 (On E0277, point at type that doesn't implement bound) - rust-lang/rust#145669 (rustdoc-search: GUI tests check for `//` in URL) - rust-lang/rust#145695 (Introduce ProjectionElem::try_map.) - rust-lang/rust#145710 (Fix the ABI parameter inconsistency issue in debug.rs for LoongArch64) - rust-lang/rust#145726 (Experiment: Reborrow trait) - rust-lang/rust#145731 (Make raw pointers work in type-based search) - rust-lang/rust#145736 (triagebot: Update style team reviewers) - rust-lang/rust#145738 (Uplift rustc_mir_transform::coverage::counters::union_find to rustc_data_structures.) - rust-lang/rust#145742 (rustdoc js: Even more typechecking improvments ) - rust-lang/rust#145743 (doc: fix some typos in comment) - rust-lang/rust#145745 (tests: Ignore basic-stepping.rs on LoongArch) - rust-lang/rust#145747 (Refactor lint buffering to avoid requiring a giant enum) - rust-lang/rust#145751 (fix(lexer): Allow '-' in the frontmatter infostring continue set) - rust-lang/rust#145761 (Add aarch64_be-unknown-hermit target) - rust-lang/rust#145762 (convert strings to symbols in attr diagnostics) - rust-lang/rust#145763 (Ship LLVM tools for the correct target when cross-compiling) - rust-lang/rust#145765 (Revert suggestions for missing methods in tuples) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_mir_transform')
6 files changed, 52 insertions, 181 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 5568d42ab8f..879a20e771d 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -16,7 +16,6 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; mod balanced_flow; pub(crate) mod node_flow; -mod union_find; /// Struct containing the results of [`prepare_bcb_counters_data`]. pub(crate) struct BcbCountersData { diff --git a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs index 91ed54b8b59..e063f75887b 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs @@ -7,13 +7,12 @@ //! (Knuth & Stevenson, 1973). use rustc_data_structures::graph; +use rustc_data_structures::union_find::UnionFind; use rustc_index::bit_set::DenseBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; pub(crate) use rustc_middle::mir::coverage::NodeFlowData; use rustc_middle::mir::coverage::Op; -use crate::coverage::counters::union_find::UnionFind; - #[cfg(test)] mod tests; diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs b/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs deleted file mode 100644 index a826a953fa6..00000000000 --- a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::cmp::Ordering; -use std::mem; - -use rustc_index::{Idx, IndexVec}; - -#[cfg(test)] -mod tests; - -/// Simple implementation of a union-find data structure, i.e. a disjoint-set -/// forest. -#[derive(Debug)] -pub(crate) struct UnionFind<Key: Idx> { - table: IndexVec<Key, UnionFindEntry<Key>>, -} - -#[derive(Debug)] -struct UnionFindEntry<Key> { - /// Transitively points towards the "root" of the set containing this key. - /// - /// Invariant: A root key is its own parent. - parent: Key, - /// When merging two "root" keys, their ranks determine which key becomes - /// the new root, to prevent the parent tree from becoming unnecessarily - /// tall. See [`UnionFind::unify`] for details. - rank: u32, -} - -impl<Key: Idx> UnionFind<Key> { - /// Creates a new disjoint-set forest containing the keys `0..num_keys`. - /// Initially, every key is part of its own one-element set. - pub(crate) fn new(num_keys: usize) -> Self { - // Initially, every key is the root of its own set, so its parent is itself. - Self { table: IndexVec::from_fn_n(|key| UnionFindEntry { parent: key, rank: 0 }, num_keys) } - } - - /// Returns the "root" key of the disjoint-set containing the given key. - /// If two keys have the same root, they belong to the same set. - /// - /// Also updates internal data structures to make subsequent `find` - /// operations faster. - pub(crate) fn find(&mut self, key: Key) -> Key { - // Loop until we find a key that is its own parent. - let mut curr = key; - while let parent = self.table[curr].parent - && curr != parent - { - // Perform "path compression" by peeking one layer ahead, and - // setting the current key's parent to that value. - // (This works even when `parent` is the root of its set, because - // of the invariant that a root is its own parent.) - let parent_parent = self.table[parent].parent; - self.table[curr].parent = parent_parent; - - // Advance by one step and continue. - curr = parent; - } - curr - } - - /// Merges the set containing `a` and the set containing `b` into one set. - /// - /// Returns the common root of both keys, after the merge. - pub(crate) fn unify(&mut self, a: Key, b: Key) -> Key { - let mut a = self.find(a); - let mut b = self.find(b); - - // If both keys have the same root, they're already in the same set, - // so there's nothing more to do. - if a == b { - return a; - }; - - // Ensure that `a` has strictly greater rank, swapping if necessary. - // If both keys have the same rank, increment the rank of `a` so that - // future unifications will also prefer `a`, leading to flatter trees. - match Ord::cmp(&self.table[a].rank, &self.table[b].rank) { - Ordering::Less => mem::swap(&mut a, &mut b), - Ordering::Equal => self.table[a].rank += 1, - Ordering::Greater => {} - } - - debug_assert!(self.table[a].rank > self.table[b].rank); - debug_assert_eq!(self.table[b].parent, b); - - // Make `a` the parent of `b`. - self.table[b].parent = a; - - a - } - - /// Takes a "snapshot" of the current state of this disjoint-set forest, in - /// the form of a vector that directly maps each key to its current root. - pub(crate) fn snapshot(&mut self) -> IndexVec<Key, Key> { - self.table.indices().map(|key| self.find(key)).collect() - } -} diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs b/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs deleted file mode 100644 index 34a4e4f8e6e..00000000000 --- a/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::UnionFind; - -#[test] -fn empty() { - let mut sets = UnionFind::<u32>::new(10); - - for i in 1..10 { - assert_eq!(sets.find(i), i); - } -} - -#[test] -fn transitive() { - let mut sets = UnionFind::<u32>::new(10); - - sets.unify(3, 7); - sets.unify(4, 2); - - assert_eq!(sets.find(7), sets.find(3)); - assert_eq!(sets.find(2), sets.find(4)); - assert_ne!(sets.find(3), sets.find(4)); - - sets.unify(7, 4); - - assert_eq!(sets.find(7), sets.find(3)); - assert_eq!(sets.find(2), sets.find(4)); - assert_eq!(sets.find(3), sets.find(4)); - - for i in [0, 1, 5, 6, 8, 9] { - assert_eq!(sets.find(i), i); - } -} diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 952da2cdf72..5a13394543b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -447,26 +447,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Projection(base, elem) => { let base = self.evaluated[base].as_ref()?; - let elem = match elem { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Downcast(name, read_variant) => { - ProjectionElem::Downcast(name, read_variant) - } - ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty), - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty), - ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty), - ProjectionElem::UnwrapUnsafeBinder(()) => { - ProjectionElem::UnwrapUnsafeBinder(ty.ty) - } - // This should have been replaced by a `ConstantIndex` earlier. - ProjectionElem::Index(_) => return None, - }; + // `Index` by constants should have been replaced by `ConstantIndex` by + // `simplify_place_projection`. + let elem = elem.try_map(|_| None, |()| ty.ty)?; self.ecx.project(base, elem).discard_err()? } Address { place, kind: _, provenance: _ } => { @@ -476,13 +459,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let local = self.locals[place.local]?; let pointer = self.evaluated[local].as_ref()?; let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?; - for proj in place.projection.iter().skip(1) { - // We have no call stack to associate a local with a value, so we cannot - // interpret indexing. - if matches!(proj, ProjectionElem::Index(_)) { - return None; - } - mplace = self.ecx.project(&mplace, proj).discard_err()?; + for elem in place.projection.iter().skip(1) { + // `Index` by constants should have been replaced by `ConstantIndex` by + // `simplify_place_projection`. + let elem = elem.try_map(|_| None, |ty| ty)?; + mplace = self.ecx.project(&mplace, elem).discard_err()?; } let pointer = mplace.to_ref(&self.ecx); ImmTy::from_immediate(pointer, ty).into() @@ -902,27 +883,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { proj: ProjectionElem<VnIndex, ()>, loc: Location, ) -> Option<PlaceElem<'tcx>> { - Some(match proj { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty), - ProjectionElem::Index(idx) => { - let Some(local) = self.try_as_local(idx, loc) else { - return None; - }; + proj.try_map( + |value| { + let local = self.try_as_local(value, loc)?; self.reused_locals.insert(local); - ProjectionElem::Index(local) - } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), - ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty), - ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty), - ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty), - }) + Some(local) + }, + |()| ty, + ) } fn simplify_aggregate_to_copy( diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index d1c2d6b508f..6f61215cee2 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -79,6 +79,7 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); + move_to_copy_pointers(tcx, body); while propagate_ssa(tcx, body) {} } @@ -87,11 +88,43 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { } } +/// The SSA analysis done by [`SsaLocals`] treats [`Operand::Move`] as a read, even though in +/// general [`Operand::Move`] represents pass-by-pointer where the callee can overwrite the +/// pointee (Miri always considers the place deinitialized). CopyProp has a similar trick to +/// turn [`Operand::Move`] into [`Operand::Copy`] when required for an optimization, but in this +/// pass we just turn all moves of pointers into copies because pointers should be by-value anyway. +fn move_to_copy_pointers<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut visitor = MoveToCopyVisitor { tcx, local_decls: &body.local_decls }; + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(bb, data); + } + + struct MoveToCopyVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>, + } + + impl<'a, 'tcx> MutVisitor<'tcx> for MoveToCopyVisitor<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { + if let Operand::Move(place) = *operand { + if place.ty(self.local_decls, self.tcx).ty.is_any_ptr() { + *operand = Operand::Copy(place); + } + } + self.super_operand(operand, loc); + } + } +} + fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let typing_env = body.typing_env(tcx); let ssa = SsaLocals::new(tcx, body, typing_env); - let mut replacer = compute_replacement(tcx, body, &ssa); + let mut replacer = compute_replacement(tcx, body, ssa); debug!(?replacer.targets); debug!(?replacer.allowed_replacements); debug!(?replacer.storage_to_remove); @@ -119,7 +152,7 @@ enum Value<'tcx> { fn compute_replacement<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - ssa: &SsaLocals, + ssa: SsaLocals, ) -> Replacer<'tcx> { let always_live_locals = always_storage_live_locals(body); @@ -138,7 +171,7 @@ fn compute_replacement<'tcx>( // reborrowed references. let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); - let fully_replaceable_locals = fully_replaceable_locals(ssa); + let fully_replaceable_locals = fully_replaceable_locals(&ssa); // Returns true iff we can use `place` as a pointee. // |
