From 5c1cb5bbc6532c114ee509db7458ebe4967153da Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 4 Feb 2023 11:48:28 +0000 Subject: [PATCH 1/2] Turn projections into copies in CopyProp. --- compiler/rustc_mir_transform/src/copy_prop.rs | 4 +-- .../copy-prop/move_projection.f.CopyProp.diff | 31 +++++++++++++++++ tests/mir-opt/copy-prop/move_projection.rs | 34 +++++++++++++++++++ ..._option_map_e2e.ezmap.PreCodegen.after.mir | 2 +- 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff create mode 100644 tests/mir-opt/copy-prop/move_projection.rs diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 4c7d45be0753e..8f16df93a56d1 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -153,8 +153,8 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand - && let Some(local) = place.as_local() - && !self.fully_moved.contains(local) + && !place.has_deref() + && !self.fully_moved.contains(place.local) { *operand = Operand::Copy(place); } diff --git a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff new file mode 100644 index 0000000000000..02308beb88af2 --- /dev/null +++ b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff @@ -0,0 +1,31 @@ +- // MIR for `f` before CopyProp ++ // MIR for `f` after CopyProp + + fn f(_1: Foo) -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/move_projection.rs:+0:17: +0:21 + let mut _2: Foo; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + let mut _3: u8; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { +- _2 = _1; // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL +- _3 = move (_2.0: u8); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL +- _0 = opaque::(move _1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44 ++ _3 = (_1.0: u8); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL ++ _0 = opaque::(_1) -> bb1; // scope 0 at $DIR/move_projection.rs:+6:13: +6:44 + // mir::Constant + // + span: $DIR/move_projection.rs:19:28: 19:34 + // + literal: Const { ty: fn(Foo) -> bool {opaque::}, val: Value() } + } + + bb1: { + _0 = opaque::(move _3) -> bb2; // scope 0 at $DIR/move_projection.rs:+9:13: +9:44 + // mir::Constant + // + span: $DIR/move_projection.rs:22:28: 22:34 + // + literal: Const { ty: fn(u8) -> bool {opaque::}, val: Value() } + } + + bb2: { + return; // scope 0 at $DIR/move_projection.rs:+12:13: +12:21 + } + } + diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs new file mode 100644 index 0000000000000..2a1bbae99a4c8 --- /dev/null +++ b/tests/mir-opt/copy-prop/move_projection.rs @@ -0,0 +1,34 @@ +// unit-test: CopyProp + +#![feature(custom_mir, core_intrinsics)] +#![allow(unused_assignments)] +extern crate core; +use core::intrinsics::mir::*; + +fn opaque(_: impl Sized) -> bool { true } + +struct Foo(u8); + +#[custom_mir(dialect = "analysis", phase = "post-cleanup")] +fn f(a: Foo) -> bool { + mir!( + { + let b = a; + // This is a move out of a copy, so must become a copy of `a.0`. + let c = Move(b.0); + Call(RET, bb1, opaque(Move(a))) + } + bb1 = { + Call(RET, ret, opaque(Move(c))) + } + ret = { + Return() + } + ) +} + +fn main() { + assert!(f(Foo(0))); +} + +// EMIT_MIR move_projection.f.CopyProp.diff 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..69d12bc2d5394 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 @@ -37,7 +37,7 @@ 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 + _4 = ((_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 From 9c5add14e7c1695bc018a941c383f01a7dde8730 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Mon, 6 Feb 2023 18:14:24 +0100 Subject: [PATCH 2/2] Comment move->copy transform. --- compiler/rustc_mir_transform/src/copy_prop.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 8f16df93a56d1..6e279232bcb48 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -153,6 +153,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand + // A move out of a projection of a copy is equivalent to a copy of the original projection. && !place.has_deref() && !self.fully_moved.contains(place.local) {