Rollup merge of #107662 - cjgillot:copy-projection, r=oli-obk

Turn projections into copies in CopyProp.

The current implementation can leave behind projections that are moved out several times.

This PR widens the check to turn such moves into copies: a move out of a projection of a copy is equivalent to a copy of the original projection.
This commit is contained in:
Matthias Krüger 2023-02-07 17:57:15 +01:00 committed by GitHub
commit 306dbaf574
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 3 deletions

View File

@ -153,8 +153,9 @@ fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Loca
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)
// 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)
{
*operand = Operand::Copy(place);
}

View File

@ -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::<Foo>(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::<Foo>(_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::<Foo>}, val: Value(<ZST>) }
}
bb1: {
_0 = opaque::<u8>(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::<u8>}, val: Value(<ZST>) }
}
bb2: {
return; // scope 0 at $DIR/move_projection.rs:+12:13: +12:21
}
}

View File

@ -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

View File

@ -34,7 +34,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
}
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
_5 = Add(_4, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
_0 = Option::<i32>::Some(move _5); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30