diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff new file mode 100644 index 00000000000..19bbbad5123 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -0,0 +1,55 @@ +- // MIR for `foo` before DataflowConstProp ++ // MIR for `foo` after DataflowConstProp + + fn foo() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Ge(move _5, const 2_u32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs new file mode 100644 index 00000000000..595f38132ee --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -0,0 +1,40 @@ +//! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning +//! the contained scalars. +//@ test-mir-pass: DataflowConstProp + +const Foo: (u32, u32) = (5, 3); + +fn foo() -> u32 { + // CHECK-LABEL: fn foo( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; + + // CHECK:bb0: { + // CHECK: [[a]] = const Foo; + // CHECK: [[b]] = [[a]]; + // CHECK: [[c]] = ([[b]].1: u32); + // CHECK: switchInt(move {{_.*}}) -> [0: bb2, otherwise: bb1]; + + // CHECK:bb1: { + // CHECK: _0 = ([[b]].0: u32); + // CHECK: goto -> bb3; + + // CHECK:bb2: { + // CHECK: _0 = const 13_u32; + // CHECK: goto -> bb3; + + let a = Foo; + // This copies the struct in `a`. We want to ensure that we do track the contents of `a` + // because we need to read `b` later. + let b = a; + let c = b.1; + if c >= 2 { b.0 } else { 13 } +} + +fn main() { + // CHECK-LABEL: fn main( + foo(); +} + +// EMIT_MIR aggregate_copy.foo.DataflowConstProp.diff diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff new file mode 100644 index 00000000000..ec62ba2feea --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-abort.diff @@ -0,0 +1,55 @@ +- // MIR for `aggregate_copy` before JumpThreading ++ // MIR for `aggregate_copy` after JumpThreading + + fn aggregate_copy() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const aggregate_copy::Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Eq(move _5, const 2_u32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff new file mode 100644 index 00000000000..ec62ba2feea --- /dev/null +++ b/tests/mir-opt/jump_threading.aggregate_copy.JumpThreading.panic-unwind.diff @@ -0,0 +1,55 @@ +- // MIR for `aggregate_copy` before JumpThreading ++ // MIR for `aggregate_copy` after JumpThreading + + fn aggregate_copy() -> u32 { + let mut _0: u32; + let _1: (u32, u32); + let mut _4: bool; + let mut _5: u32; + scope 1 { + debug a => _1; + let _2: (u32, u32); + scope 2 { + debug b => _2; + let _3: u32; + scope 3 { + debug c => _3; + } + } + } + + bb0: { + StorageLive(_1); + _1 = const aggregate_copy::Foo; + StorageLive(_2); + _2 = _1; + StorageLive(_3); + _3 = (_2.1: u32); + StorageLive(_4); + StorageLive(_5); + _5 = _3; + _4 = Eq(move _5, const 2_u32); + switchInt(move _4) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + StorageDead(_5); + _0 = (_2.0: u32); + goto -> bb3; + } + + bb2: { + StorageDead(_5); + _0 = const 13_u32; + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index b4c13371680..59b5b2c6eea 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -506,6 +506,21 @@ fn assume(a: u8, b: bool) -> u8 { } } +/// Verify that jump threading succeeds seeing through copies of aggregates. +fn aggregate_copy() -> u32 { + // CHECK-LABEL: fn aggregate_copy( + // CHECK: switchInt( + + const Foo: (u32, u32) = (5, 3); + + let a = Foo; + // This copies a tuple, we want to ensure that the threading condition on `b.1` propagates to a + // condition on `a.1`. + let b = a; + let c = b.1; + if c == 2 { b.0 } else { 13 } +} + fn main() { // CHECK-LABEL: fn main( too_complex(Ok(0)); @@ -534,3 +549,4 @@ fn main() { // EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff // EMIT_MIR jump_threading.aggregate.JumpThreading.diff // EMIT_MIR jump_threading.assume.JumpThreading.diff +// EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff