From 0e0a71a3931bbfe5c296e9f55adabb2585974c2c Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 3 Apr 2020 18:40:08 -0400 Subject: [PATCH 1/5] Add test case --- .../mir-opt/simplify-locals-fixedpoint.rs | 15 +++++ .../rustc.foo.SimplifyLocals.diff | 65 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/test/mir-opt/simplify-locals-fixedpoint.rs create mode 100644 src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff diff --git a/src/test/mir-opt/simplify-locals-fixedpoint.rs b/src/test/mir-opt/simplify-locals-fixedpoint.rs new file mode 100644 index 0000000000000..aa5bc345359eb --- /dev/null +++ b/src/test/mir-opt/simplify-locals-fixedpoint.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmir-opt-level=1 + +fn foo() { + if let (Some(a), None) = (Option::::None, Option::::None) { + if a > 42u8 { + + } + } +} + +fn main() { + foo::<()>(); +} + +// EMIT_MIR rustc.foo.SimplifyLocals.diff diff --git a/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff new file mode 100644 index 0000000000000..89326e8e3f675 --- /dev/null +++ b/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff @@ -0,0 +1,65 @@ +- // MIR for `foo` before SimplifyLocals ++ // MIR for `foo` after SimplifyLocals + + fn foo() -> () { + let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-fixedpoint.rs:3:13: 3:13 + let mut _1: (std::option::Option, std::option::Option); // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + let mut _2: std::option::Option; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + let mut _3: std::option::Option; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + let mut _4: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + let mut _5: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 + let _6: u8; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + let mut _7: bool; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 + let mut _8: u8; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 + scope 1 { + debug a => _6; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + } + + bb0: { + StorageLive(_1); // bb0[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + StorageLive(_2); // bb0[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + discriminant(_2) = 0; // bb0[2]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49 + StorageLive(_3); // bb0[3]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + discriminant(_3) = 0; // bb0[4]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68 + (_1.0: std::option::Option) = move _2; // bb0[5]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + (_1.1: std::option::Option) = move _3; // bb0[6]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69 + StorageDead(_3); // bb0[7]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69 + StorageDead(_2); // bb0[8]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69 + _5 = discriminant((_1.0: std::option::Option)); // bb0[9]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 + switchInt(move _5) -> [1isize: bb1, otherwise: bb3]; // bb0[10]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 + } + + bb1: { + _4 = discriminant((_1.1: std::option::Option)); // bb1[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + switchInt(move _4) -> [0isize: bb2, otherwise: bb3]; // bb1[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + } + + bb2: { + StorageLive(_6); // bb2[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + _6 = (((_1.0: std::option::Option) as Some).0: u8); // bb2[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + StorageLive(_7); // bb2[2]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 + StorageLive(_8); // bb2[3]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 + _8 = _6; // bb2[4]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 + _7 = Gt(move _8, const 42u8); // bb2[5]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x2a)) + // mir::Constant + // + span: $DIR/simplify-locals-fixedpoint.rs:5:16: 5:20 + // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } + StorageDead(_8); // bb2[6]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20 + StorageDead(_7); // bb2[7]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 + StorageDead(_6); // bb2[8]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 + goto -> bb3; // bb2[9]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 + } + + bb3: { + drop(_1) -> bb4; // bb3[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 + } + + bb4: { + StorageDead(_1); // bb4[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 + return; // bb4[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:2: 9:2 + } + } + From 7c0802b34124b777f2cf414a4d88a8576645c3c3 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 3 Apr 2020 19:31:59 -0400 Subject: [PATCH 2/5] Remove other Rvalues --- src/librustc_mir/transform/simplify.rs | 42 ++++++++--- .../32bit/rustc.main.ConstProp.after.mir | 16 ++-- .../64bit/rustc.main.ConstProp.after.mir | 14 ++-- .../32bit/rustc.main.SimplifyLocals.after.mir | 60 +++------------ .../64bit/rustc.main.SimplifyLocals.after.mir | 60 +++------------ .../rustc.foo.SimplifyLocals.diff | 73 ++++++++++++++----- 6 files changed, 120 insertions(+), 145 deletions(-) diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index c0da2c446d65f..da79a065eb797 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -368,21 +368,39 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { if location.statement_index != block.statements.len() { let stmt = &block.statements[location.statement_index]; + fn can_skip_constant(c: &ty::Const<'tcx>) -> bool { + // Keep assignments from unevaluated constants around, since the + // evaluation may report errors, even if the use of the constant + // is dead code. + !matches!(c.val, ty::ConstKind::Unevaluated(..)) + } + + fn can_skip_operand(o: &Operand<'_>) -> bool { + match o { + Operand::Copy(p) | Operand::Move(p) => !p.is_indirect(), + Operand::Constant(c) => can_skip_constant(c.literal), + } + } + if let StatementKind::Assign(box (dest, rvalue)) = &stmt.kind { if !dest.is_indirect() && dest.local == *local { - if let Rvalue::Use(Operand::Constant(c)) = rvalue { - match c.literal.val { - // Keep assignments from unevaluated constants around, since the - // evaluation may report errors, even if the use of the constant - // is dead code. - ty::ConstKind::Unevaluated(..) => {} - _ => { - trace!("skipping store of const value {:?} to {:?}", c, dest); - return; - } + let can_skip = match rvalue { + Rvalue::Use(op) => can_skip_operand(op), + Rvalue::Discriminant(_) => true, + Rvalue::BinaryOp(_, l, r) | Rvalue::CheckedBinaryOp(_, l, r) => { + can_skip_operand(l) && can_skip_operand(r) } - } else if let Rvalue::Discriminant(d) = rvalue { - trace!("skipping store of discriminant value {:?} to {:?}", d, dest); + Rvalue::Repeat(op, c) => can_skip_operand(op) && can_skip_constant(c), + Rvalue::AddressOf(_, _) => true, + Rvalue::Len(_) => true, + Rvalue::UnaryOp(_, op) => can_skip_operand(op), + Rvalue::Aggregate(_, operands) => operands.iter().all(can_skip_operand), + + _ => false, + }; + + if can_skip { + trace!("skipping store of {:?} to {:?}", rvalue, dest); return; } } diff --git a/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir index 323134553c195..63e6b8358a534 100644 --- a/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir +++ b/src/test/mir-opt/const_allocation3/32bit/rustc.main.ConstProp.after.mir @@ -30,30 +30,30 @@ fn main() -> () { } alloc0 (static: FOO, size: 4, align: 4) { - ╾alloc10+0╼ │ ╾──╼ + ╾alloc9+0─╼ │ ╾──╼ } -alloc10 (size: 168, align: 1) { +alloc9 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾alloc5+0─╼ │ ............╾──╼ + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾alloc4+0─╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾alloc7+0─╼ 00 00 │ ..........╾──╼.. - 0x90 │ ╾alloc8+99╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ + 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾alloc6+0─╼ 00 00 │ ..........╾──╼.. + 0x90 │ ╾alloc7+99╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ 0xa0 │ 00 00 00 00 00 00 00 00 │ ........ } -alloc5 (size: 4, align: 4) { +alloc4 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc7 (fn: main) +alloc6 (fn: main) -alloc8 (size: 100, align: 1) { +alloc7 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir b/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir index 952fe8336cd0e..7dea5c664d858 100644 --- a/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir +++ b/src/test/mir-opt/const_allocation3/64bit/rustc.main.ConstProp.after.mir @@ -30,12 +30,12 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 8) { - ╾──────alloc10+0──────╼ │ ╾──────╼ + ╾──────alloc9+0───────╼ │ ╾──────╼ } -alloc10 (size: 180, align: 1) { +alloc9 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc5+0─ │ ............╾─── + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4+0─ │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ @@ -43,18 +43,18 @@ alloc10 (size: 180, align: 1) { 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─ - 0x90 │ ────alloc7+0────╼ 00 00 ╾──────alloc8+99──────╼ │ ─────╼..╾──────╼ + 0x90 │ ────alloc6+0────╼ 00 00 ╾──────alloc7+99──────╼ │ ─────╼..╾──────╼ 0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0xb0 │ 00 00 00 00 │ .... } -alloc5 (size: 4, align: 4) { +alloc4 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc7 (fn: main) +alloc6 (fn: main) -alloc8 (size: 100, align: 1) { +alloc7 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.SimplifyLocals.after.mir b/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.SimplifyLocals.after.mir index 5e2a8af060be8..f8aea27df6660 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.SimplifyLocals.after.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable/32bit/rustc.main.SimplifyLocals.after.mir @@ -3,15 +3,14 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - let mut _3: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:31 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - let _4: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => _4; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } @@ -26,70 +25,31 @@ fn main() -> () { // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) } StorageLive(_2); // bb0[2]: scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - StorageLive(_3); // bb0[3]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 - _3 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32]; // bb0[4]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:14: 13:15 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:17: 13:18 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000002)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:20: 13:21 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000003)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:23: 13:24 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000004)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:26: 13:27 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000005)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:29: 13:30 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) } - _2 = const 3i32; // bb0[5]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _2 = const 3i32; // bb0[3]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 // ty::Const // + ty: i32 // + val: Value(Scalar(0x00000003)) // mir::Constant // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34 // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) } - StorageDead(_3); // bb0[6]: scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35 - StorageLive(_4); // bb0[7]: scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 - _4 = const 42u32; // bb0[8]: scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 + StorageLive(_3); // bb0[4]: scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + _3 = const 42u32; // bb0[5]: scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 // ty::Const // + ty: u32 // + val: Value(Scalar(0x0000002a)) // mir::Constant // + span: $DIR/optimizes_into_variable.rs:14:13: 14:38 // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) } - _0 = const (); // bb0[9]: scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 + _0 = const (); // bb0[6]: scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant // + span: $DIR/optimizes_into_variable.rs:11:11: 15:2 // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_4); // bb0[10]: scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_2); // bb0[11]: scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_1); // bb0[12]: scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - return; // bb0[13]: scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 + StorageDead(_3); // bb0[7]: scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_2); // bb0[8]: scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // bb0[9]: scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + return; // bb0[10]: scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.SimplifyLocals.after.mir b/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.SimplifyLocals.after.mir index 5e2a8af060be8..f8aea27df6660 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.SimplifyLocals.after.mir +++ b/src/test/mir-opt/const_prop/optimizes_into_variable/64bit/rustc.main.SimplifyLocals.after.mir @@ -3,15 +3,14 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/optimizes_into_variable.rs:11:11: 11:11 let _1: i32; // in scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - let mut _3: [i32; 6]; // in scope 0 at $DIR/optimizes_into_variable.rs:13:13: 13:31 scope 1 { debug x => _1; // in scope 1 at $DIR/optimizes_into_variable.rs:12:9: 12:10 let _2: i32; // in scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 scope 2 { debug y => _2; // in scope 2 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - let _4: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + let _3: u32; // in scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 scope 3 { - debug z => _4; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + debug z => _3; // in scope 3 at $DIR/optimizes_into_variable.rs:14:9: 14:10 } } } @@ -26,70 +25,31 @@ fn main() -> () { // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) } StorageLive(_2); // bb0[2]: scope 1 at $DIR/optimizes_into_variable.rs:13:9: 13:10 - StorageLive(_3); // bb0[3]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 - _3 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32]; // bb0[4]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:31 - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000000)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:14: 13:15 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000001)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:17: 13:18 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000002)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:20: 13:21 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000003)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:23: 13:24 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000004)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:26: 13:27 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) } - // ty::Const - // + ty: i32 - // + val: Value(Scalar(0x00000005)) - // mir::Constant - // + span: $DIR/optimizes_into_variable.rs:13:29: 13:30 - // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) } - _2 = const 3i32; // bb0[5]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _2 = const 3i32; // bb0[3]: scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 // ty::Const // + ty: i32 // + val: Value(Scalar(0x00000003)) // mir::Constant // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34 // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) } - StorageDead(_3); // bb0[6]: scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35 - StorageLive(_4); // bb0[7]: scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 - _4 = const 42u32; // bb0[8]: scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 + StorageLive(_3); // bb0[4]: scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10 + _3 = const 42u32; // bb0[5]: scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38 // ty::Const // + ty: u32 // + val: Value(Scalar(0x0000002a)) // mir::Constant // + span: $DIR/optimizes_into_variable.rs:14:13: 14:38 // + literal: Const { ty: u32, val: Value(Scalar(0x0000002a)) } - _0 = const (); // bb0[9]: scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 + _0 = const (); // bb0[6]: scope 0 at $DIR/optimizes_into_variable.rs:11:11: 15:2 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant // + span: $DIR/optimizes_into_variable.rs:11:11: 15:2 // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_4); // bb0[10]: scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_2); // bb0[11]: scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - StorageDead(_1); // bb0[12]: scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 - return; // bb0[13]: scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 + StorageDead(_3); // bb0[7]: scope 2 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_2); // bb0[8]: scope 1 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + StorageDead(_1); // bb0[9]: scope 0 at $DIR/optimizes_into_variable.rs:15:1: 15:2 + return; // bb0[10]: scope 0 at $DIR/optimizes_into_variable.rs:15:2: 15:2 } } diff --git a/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff index 89326e8e3f675..bc59be48eee0f 100644 --- a/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify-locals-fixedpoint/rustc.foo.SimplifyLocals.diff @@ -26,40 +26,77 @@ StorageDead(_3); // bb0[7]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69 StorageDead(_2); // bb0[8]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69 _5 = discriminant((_1.0: std::option::Option)); // bb0[9]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 - switchInt(move _5) -> [1isize: bb1, otherwise: bb3]; // bb0[10]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 + switchInt(move _5) -> [1isize: bb2, otherwise: bb1]; // bb0[10]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:13: 4:20 } bb1: { - _4 = discriminant((_1.1: std::option::Option)); // bb1[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 - switchInt(move _4) -> [0isize: bb2, otherwise: bb3]; // bb1[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + _0 = const (); // bb1[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 + // + literal: Const { ty: (), val: Value(Scalar()) } + goto -> bb7; // bb1[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 } bb2: { - StorageLive(_6); // bb2[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 - _6 = (((_1.0: std::option::Option) as Some).0: u8); // bb2[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 - StorageLive(_7); // bb2[2]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 - StorageLive(_8); // bb2[3]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 - _8 = _6; // bb2[4]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 - _7 = Gt(move _8, const 42u8); // bb2[5]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 + _4 = discriminant((_1.1: std::option::Option)); // bb2[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + switchInt(move _4) -> [0isize: bb3, otherwise: bb1]; // bb2[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:22: 4:26 + } + + bb3: { + StorageLive(_6); // bb3[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + _6 = (((_1.0: std::option::Option) as Some).0: u8); // bb3[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:18: 4:19 + StorageLive(_7); // bb3[2]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 + StorageLive(_8); // bb3[3]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 + _8 = _6; // bb3[4]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:13 + _7 = Gt(move _8, const 42u8); // bb3[5]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:12: 5:20 // ty::Const // + ty: u8 // + val: Value(Scalar(0x2a)) // mir::Constant // + span: $DIR/simplify-locals-fixedpoint.rs:5:16: 5:20 // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } - StorageDead(_8); // bb2[6]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20 - StorageDead(_7); // bb2[7]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 - StorageDead(_6); // bb2[8]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 - goto -> bb3; // bb2[9]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 + StorageDead(_8); // bb3[6]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:19: 5:20 + switchInt(_7) -> [false: bb4, otherwise: bb5]; // bb3[7]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 } - bb3: { - drop(_1) -> bb4; // bb3[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 + bb4: { + _0 = const (); // bb4[0]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 + // + literal: Const { ty: (), val: Value(Scalar()) } + goto -> bb6; // bb4[1]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 } - bb4: { - StorageDead(_1); // bb4[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 - return; // bb4[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:2: 9:2 + bb5: { + _0 = const (); // bb5[0]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:21: 7:10 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/simplify-locals-fixedpoint.rs:5:21: 7:10 + // + literal: Const { ty: (), val: Value(Scalar()) } + goto -> bb6; // bb5[1]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:5:9: 7:10 + } + + bb6: { + StorageDead(_7); // bb6[0]: scope 1 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 + StorageDead(_6); // bb6[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:8:5: 8:6 + goto -> bb7; // bb6[2]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:5: 8:6 + } + + bb7: { + drop(_1) -> bb8; // bb7[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 + } + + bb8: { + StorageDead(_1); // bb8[0]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:1: 9:2 + return; // bb8[1]: scope 0 at $DIR/simplify-locals-fixedpoint.rs:9:2: 9:2 } } From de3cf6e8a472bf67df278cfae8986afdcc215c18 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 3 Apr 2020 20:28:07 -0400 Subject: [PATCH 3/5] Run `SimplifyLocals` iteratively until we get to a fixedpoint --- src/librustc_mir/transform/simplify.rs | 158 ++++++++++++++++++++----- 1 file changed, 131 insertions(+), 27 deletions(-) diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index da79a065eb797..31d902bef1d6d 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -306,49 +306,74 @@ pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) { trace!("running SimplifyLocals on {:?}", source); - let locals = { + + let mut used_locals = { let read_only_cache = read_only!(body); - let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()), body }; + let mut marker = DeclMarker::new(body); marker.visit_body(&read_only_cache); - // Return pointer and arguments are always live - marker.locals.insert(RETURN_PLACE); - for arg in body.args_iter() { - marker.locals.insert(arg); - } - marker.locals + marker.local_counts }; - let map = make_local_map(&mut body.local_decls, locals); - // Update references to all vars and tmps now - LocalUpdater { map, tcx }.visit_body(body); - body.local_decls.shrink_to_fit(); + let arg_count = body.arg_count; + + loop { + let mut remove_statements = RemoveStatements::new(&mut used_locals, arg_count, tcx); + remove_statements.visit_body(body); + + if !remove_statements.modified { + break; + } + } + + let map = make_local_map(&mut body.local_decls, used_locals, arg_count); + + // Only bother running the `LocalUpdater` if we actually found locals to remove. + if map.iter().any(Option::is_none) { + // Update references to all vars and tmps now + let mut updater = LocalUpdater { map, tcx }; + updater.visit_body(body); + + body.local_decls.shrink_to_fit(); + } } } /// Construct the mapping while swapping out unused stuff out from the `vec`. fn make_local_map( - vec: &mut IndexVec, - mask: BitSet, + local_decls: &mut IndexVec, + used_locals: IndexVec, + arg_count: usize, ) -> IndexVec> { - let mut map: IndexVec> = IndexVec::from_elem(None, &*vec); + let mut map: IndexVec> = IndexVec::from_elem(None, &*local_decls); let mut used = Local::new(0); - for alive_index in mask.iter() { + for (alive_index, count) in used_locals.iter_enumerated() { + // The `RETURN_PLACE` and arguments are always live. + if alive_index.as_usize() > arg_count && *count == 0 { + continue; + } + map[alive_index] = Some(used); if alive_index != used { - vec.swap(alive_index, used); + local_decls.swap(alive_index, used); } used.increment_by(1); } - vec.truncate(used.index()); + local_decls.truncate(used.index()); map } struct DeclMarker<'a, 'tcx> { - pub locals: BitSet, + pub local_counts: IndexVec, pub body: &'a Body<'tcx>, } +impl<'a, 'tcx> DeclMarker<'a, 'tcx> { + pub fn new(body: &'a Body<'tcx>) -> Self { + Self { local_counts: IndexVec::from_elem(0, &body.local_decls), body } + } +} + impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) { // Ignore storage markers altogether, they get removed along with their otherwise unused @@ -408,29 +433,108 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { } } - self.locals.insert(*local); + self.local_counts[*local] += 1; } } -struct LocalUpdater<'tcx> { - map: IndexVec>, +struct StatementDeclMarker<'a, 'tcx> { + used_locals: IndexVec, + statement: &'a Statement<'tcx>, +} + +impl<'a, 'tcx> StatementDeclMarker<'a, 'tcx> { + pub fn new(local_count: usize, statement: &'a Statement<'tcx>) -> Self { + Self { used_locals: IndexVec::from_elem_n(0, local_count), statement } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for StatementDeclMarker<'a, 'tcx> { + fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) { + // Skip the lvalue for assignments + if let StatementKind::Assign(box (p, _)) = self.statement.kind { + if p.local == *local && context.is_place_assignment() { + return; + } + } + + self.used_locals[*local] += 1; + } +} + +struct RemoveStatements<'a, 'tcx> { + used_locals: &'a mut IndexVec, + arg_count: usize, tcx: TyCtxt<'tcx>, + modified: bool, } -impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { +impl<'a, 'tcx> RemoveStatements<'a, 'tcx> { + fn new( + used_locals: &'a mut IndexVec, + arg_count: usize, + tcx: TyCtxt<'tcx>, + ) -> Self { + Self { used_locals, arg_count, tcx, modified: false } + } + + fn keep_local(&self, l: Local) -> bool { + trace!("keep_local({:?}): count: {:?}", l, self.used_locals[l]); + l.as_usize() <= self.arg_count || self.used_locals[l] != 0 + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for RemoveStatements<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { // Remove unnecessary StorageLive and StorageDead annotations. - data.statements.retain(|stmt| match &stmt.kind { - StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(), - StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(), - _ => true, + let mut i = 0usize; + data.statements.retain(|stmt| { + let keep = match &stmt.kind { + StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { + self.keep_local(*l) + } + StatementKind::Assign(box (place, _)) => self.keep_local(place.local), + _ => true, + }; + + if !keep { + trace!("removing statement {:?}", stmt); + self.modified = true; + + let mut visitor = StatementDeclMarker::new(self.used_locals.len(), stmt); + visitor.visit_statement(stmt, Location { block, statement_index: i }); + + for (local, count) in visitor.used_locals.iter_enumerated() { + let used_count = &mut self.used_locals[local]; + + // If this is the local we're removing... + if *used_count != 0 { + *used_count -= count; + } + } + } + + i += 1; + + keep }); + self.super_basic_block_data(block, data); } +} + +struct LocalUpdater<'tcx> { + map: IndexVec>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); From da8f3bbf32e6a67b1c1370465592776a1d999ad0 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 13 Apr 2020 21:02:03 -0400 Subject: [PATCH 4/5] Directly modify the `used_locals` vec Fixes perf regression in `optimized_mir` query --- src/librustc_mir/transform/simplify.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 31d902bef1d6d..45e2e0c259674 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -438,13 +438,16 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { } struct StatementDeclMarker<'a, 'tcx> { - used_locals: IndexVec, + used_locals: &'a mut IndexVec, statement: &'a Statement<'tcx>, } impl<'a, 'tcx> StatementDeclMarker<'a, 'tcx> { - pub fn new(local_count: usize, statement: &'a Statement<'tcx>) -> Self { - Self { used_locals: IndexVec::from_elem_n(0, local_count), statement } + pub fn new( + used_locals: &'a mut IndexVec, + statement: &'a Statement<'tcx>, + ) -> Self { + Self { used_locals, statement } } } @@ -457,7 +460,11 @@ impl<'a, 'tcx> Visitor<'tcx> for StatementDeclMarker<'a, 'tcx> { } } - self.used_locals[*local] += 1; + let use_count = &mut self.used_locals[*local]; + // If this is the local we're removing... + if *use_count != 0 { + *use_count -= 1; + } } } @@ -504,17 +511,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RemoveStatements<'a, 'tcx> { trace!("removing statement {:?}", stmt); self.modified = true; - let mut visitor = StatementDeclMarker::new(self.used_locals.len(), stmt); + let mut visitor = StatementDeclMarker::new(self.used_locals, stmt); visitor.visit_statement(stmt, Location { block, statement_index: i }); - - for (local, count) in visitor.used_locals.iter_enumerated() { - let used_count = &mut self.used_locals[local]; - - // If this is the local we're removing... - if *used_count != 0 { - *used_count -= count; - } - } } i += 1; From 9666d31bcf57190864fc61a95d2dab7ae3e51cdf Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 16 Apr 2020 08:34:37 -0400 Subject: [PATCH 5/5] Respond to code review feedback - Remove reads of indirect `Place`s - Add comments explaining what the algorithm does --- src/librustc_mir/transform/simplify.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 45e2e0c259674..c4971b2565511 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -307,6 +307,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) { trace!("running SimplifyLocals on {:?}", source); + // First, we're going to get a count of *actual* uses for every `Local`. + // Take a look at `DeclMarker::visit_local()` to see exactly what is ignored. let mut used_locals = { let read_only_cache = read_only!(body); let mut marker = DeclMarker::new(body); @@ -317,6 +319,11 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals { let arg_count = body.arg_count; + // Next, we're going to remove any `Local` with zero actual uses. When we remove those + // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` + // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from + // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a + // fixedpoint where there are no more unused locals. loop { let mut remove_statements = RemoveStatements::new(&mut used_locals, arg_count, tcx); remove_statements.visit_body(body); @@ -326,6 +333,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals { } } + // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. let map = make_local_map(&mut body.local_decls, used_locals, arg_count); // Only bother running the `LocalUpdater` if we actually found locals to remove. @@ -402,7 +410,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> { fn can_skip_operand(o: &Operand<'_>) -> bool { match o { - Operand::Copy(p) | Operand::Move(p) => !p.is_indirect(), + Operand::Copy(_) | Operand::Move(_) => true, Operand::Constant(c) => can_skip_constant(c.literal), } }