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:
commit
306dbaf574
@ -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);
|
||||
}
|
||||
|
31
tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
Normal file
31
tests/mir-opt/copy-prop/move_projection.f.CopyProp.diff
Normal 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
|
||||
}
|
||||
}
|
||||
|
34
tests/mir-opt/copy-prop/move_projection.rs
Normal file
34
tests/mir-opt/copy-prop/move_projection.rs
Normal 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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user