about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2025-01-05 23:27:24 -0800
committerScott McMurray <scottmcm@users.noreply.github.com>2025-01-08 18:46:31 -0800
commitb421a563644dafdb8a5a9c48fe21c4a449da18fa (patch)
treeff4482b81cbc881ca12d30f247fef09f30583fed
parent293f8e8941e77c6372abd787fe564e9bf895445e (diff)
downloadrust-b421a563644dafdb8a5a9c48fe21c4a449da18fa.tar.gz
rust-b421a563644dafdb8a5a9c48fe21c4a449da18fa.zip
Make the aggregate-then-transmute handling more general
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs22
-rw-r--r--tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff393
-rw-r--r--tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff393
-rw-r--r--tests/mir-opt/gvn.rs14
4 files changed, 514 insertions, 308 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 7c600fc1ceb..71bec38c405 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1370,12 +1370,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         loop {
             let mut was_updated_this_iteration = false;
 
-            // Transmuting `*const T` <=> `*mut T` is just a pointer cast,
-            // which we might be able to merge with other ones later.
+            // Transmuting between raw pointers is just a pointer cast so long as
+            // they have the same metadata type (like `*const i32` <=> `*mut u64`
+            // or `*mut [i32]` <=> `*const [u64]`), including the common special
+            // case of `*const T` <=> `*mut T`.
             if let Transmute = kind
-                && let ty::RawPtr(from_pointee, _) = from.kind()
-                && let ty::RawPtr(to_pointee, _) = to.kind()
-                && from_pointee == to_pointee
+                && from.is_unsafe_ptr()
+                && to.is_unsafe_ptr()
+                && self.pointers_have_same_metadata(from, to)
             {
                 *kind = PtrToPtr;
                 was_updated_this_iteration = true;
@@ -1400,15 +1402,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             // Aggregate-then-Transmute can just transmute the original field value,
             // so long as the bytes of a value from only from a single field.
             if let Transmute = kind
-                && let Value::Aggregate(
-                    AggregateTy::Def(aggregate_did, aggregate_args),
-                    variant_idx,
-                    field_values,
-                ) = self.get(value)
-                && let aggregate_ty =
-                    self.tcx.type_of(aggregate_did).instantiate(self.tcx, aggregate_args)
+                && let Value::Aggregate(_aggregate_ty, variant_idx, field_values) = self.get(value)
                 && let Some((field_idx, field_ty)) =
-                    self.value_is_all_in_one_field(aggregate_ty, *variant_idx)
+                    self.value_is_all_in_one_field(from, *variant_idx)
             {
                 from = field_ty;
                 value = field_values[field_idx.as_usize()];
diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff
index 1f929180247..5ae575f300a 100644
--- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-abort.diff
@@ -1,61 +1,87 @@
 - // MIR for `aggregate_struct_then_transmute` before GVN
 + // MIR for `aggregate_struct_then_transmute` after GVN
   
-  fn aggregate_struct_then_transmute(_1: u16) -> () {
+  fn aggregate_struct_then_transmute(_1: u16, _2: *const u8) -> () {
       debug id => _1;
+      debug thin => _2;
       let mut _0: ();
-      let _2: MyId;
-      let mut _3: u16;
-      let _4: ();
-      let mut _5: u16;
-      let mut _6: MyId;
-      let mut _8: u16;
-      let mut _9: std::marker::PhantomData<std::string::String>;
-      let _10: ();
-      let mut _11: u16;
-      let mut _12: TypedId<std::string::String>;
-      let mut _14: u16;
-      let _15: ();
-      let mut _16: u16;
-      let mut _17: std::result::Result<Never, u16>;
-      let mut _19: u16;
-      let _20: ();
-      let mut _21: u32;
-      let mut _22: std::option::Option<u16>;
-      let mut _24: u16;
-      let _25: ();
-      let mut _26: i16;
-      let mut _27: MyId;
-      let mut _29: u16;
+      let _3: MyId;
+      let mut _4: u16;
+      let _5: ();
+      let mut _6: u16;
+      let mut _7: MyId;
+      let mut _9: u16;
+      let mut _10: std::marker::PhantomData<std::string::String>;
+      let _11: ();
+      let mut _12: u16;
+      let mut _13: TypedId<std::string::String>;
+      let mut _15: u16;
+      let _16: ();
+      let mut _17: u16;
+      let mut _18: std::result::Result<Never, u16>;
+      let mut _20: u16;
+      let _21: ();
+      let mut _22: u32;
+      let mut _23: std::option::Option<u16>;
+      let mut _25: u16;
+      let _26: ();
+      let mut _27: i16;
+      let mut _28: MyId;
       let mut _30: u16;
-      let _31: ();
-      let mut _32: u32;
-      let mut _33: aggregate_struct_then_transmute::Pair;
-      let mut _35: u16;
+      let mut _31: u16;
+      let _32: ();
+      let mut _33: u32;
+      let mut _34: aggregate_struct_then_transmute::Pair;
       let mut _36: u16;
-      let _37: ();
-      let mut _38: u16;
-      let mut _39: aggregate_struct_then_transmute::Pair;
+      let mut _37: u16;
+      let _38: ();
+      let mut _39: u16;
+      let mut _40: aggregate_struct_then_transmute::Pair;
+      let mut _42: u16;
+      let _43: ();
+      let mut _44: u16;
+      let mut _45: (u16,);
+      let mut _47: u16;
+      let _48: ();
+      let mut _49: u16;
+      let mut _50: [u16; 1];
+      let mut _52: *const u8;
+      let mut _53: ();
+      let _54: ();
+      let mut _55: *const u8;
+      let mut _56: *const i32;
       scope 1 {
-          debug a => _2;
-          let _7: TypedId<std::string::String>;
+          debug a => _3;
+          let _8: TypedId<std::string::String>;
           scope 2 {
-              debug b => _7;
-              let _13: std::result::Result<Never, u16>;
+              debug b => _8;
+              let _14: std::result::Result<Never, u16>;
               scope 3 {
-                  debug c => _13;
-                  let _18: std::option::Option<u16>;
+                  debug c => _14;
+                  let _19: std::option::Option<u16>;
                   scope 4 {
-                      debug d => _18;
-                      let _23: MyId;
+                      debug d => _19;
+                      let _24: MyId;
                       scope 5 {
-                          debug e => _23;
-                          let _28: aggregate_struct_then_transmute::Pair;
+                          debug e => _24;
+                          let _29: aggregate_struct_then_transmute::Pair;
                           scope 6 {
-                              debug f => _28;
-                              let _34: aggregate_struct_then_transmute::Pair;
+                              debug f => _29;
+                              let _35: aggregate_struct_then_transmute::Pair;
                               scope 7 {
-                                  debug g => _34;
+                                  debug g => _35;
+                                  let _41: (u16,);
+                                  scope 8 {
+                                      debug h => _41;
+                                      let _46: [u16; 1];
+                                      scope 9 {
+                                          debug i => _46;
+                                          let _51: *const i32;
+                                          scope 10 {
+                                              debug j => _51;
+                                          }
+                                      }
+                                  }
                               }
                           }
                       }
@@ -65,172 +91,245 @@
       }
   
       bb0: {
--         StorageLive(_2);
+-         StorageLive(_3);
 +         nop;
-          StorageLive(_3);
-          _3 = copy _1;
--         _2 = MyId(move _3);
-+         _2 = MyId(copy _1);
-          StorageDead(_3);
           StorageLive(_4);
+          _4 = copy _1;
+-         _3 = MyId(move _4);
++         _3 = MyId(copy _1);
+          StorageDead(_4);
           StorageLive(_5);
           StorageLive(_6);
--         _6 = move _2;
--         _5 = move _6 as u16 (Transmute);
-+         _6 = copy _2;
-+         _5 = copy _1;
-          StorageDead(_6);
--         _4 = opaque::<u16>(move _5) -> [return: bb1, unwind unreachable];
-+         _4 = opaque::<u16>(copy _1) -> [return: bb1, unwind unreachable];
+          StorageLive(_7);
+-         _7 = move _3;
+-         _6 = move _7 as u16 (Transmute);
++         _7 = copy _3;
++         _6 = copy _1;
+          StorageDead(_7);
+-         _5 = opaque::<u16>(move _6) -> [return: bb1, unwind unreachable];
++         _5 = opaque::<u16>(copy _1) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
+          StorageDead(_6);
           StorageDead(_5);
-          StorageDead(_4);
--         StorageLive(_7);
+-         StorageLive(_8);
 +         nop;
-          StorageLive(_8);
-          _8 = copy _1;
           StorageLive(_9);
--         _9 = PhantomData::<String>;
--         _7 = TypedId::<String>(move _8, move _9);
-+         _9 = const PhantomData::<String>;
-+         _7 = TypedId::<String>(copy _1, const PhantomData::<String>);
-          StorageDead(_9);
-          StorageDead(_8);
+          _9 = copy _1;
           StorageLive(_10);
+-         _10 = PhantomData::<String>;
+-         _8 = TypedId::<String>(move _9, move _10);
++         _10 = const PhantomData::<String>;
++         _8 = TypedId::<String>(copy _1, const PhantomData::<String>);
+          StorageDead(_10);
+          StorageDead(_9);
           StorageLive(_11);
           StorageLive(_12);
--         _12 = move _7;
--         _11 = move _12 as u16 (Transmute);
-+         _12 = copy _7;
-+         _11 = copy _1;
-          StorageDead(_12);
--         _10 = opaque::<u16>(move _11) -> [return: bb2, unwind unreachable];
-+         _10 = opaque::<u16>(copy _1) -> [return: bb2, unwind unreachable];
+          StorageLive(_13);
+-         _13 = move _8;
+-         _12 = move _13 as u16 (Transmute);
++         _13 = copy _8;
++         _12 = copy _1;
+          StorageDead(_13);
+-         _11 = opaque::<u16>(move _12) -> [return: bb2, unwind unreachable];
++         _11 = opaque::<u16>(copy _1) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
+          StorageDead(_12);
           StorageDead(_11);
-          StorageDead(_10);
--         StorageLive(_13);
+-         StorageLive(_14);
 +         nop;
-          StorageLive(_14);
-          _14 = copy _1;
--         _13 = Result::<Never, u16>::Err(move _14);
-+         _13 = Result::<Never, u16>::Err(copy _1);
-          StorageDead(_14);
           StorageLive(_15);
+          _15 = copy _1;
+-         _14 = Result::<Never, u16>::Err(move _15);
++         _14 = Result::<Never, u16>::Err(copy _1);
+          StorageDead(_15);
           StorageLive(_16);
           StorageLive(_17);
--         _17 = move _13;
--         _16 = move _17 as u16 (Transmute);
-+         _17 = copy _13;
-+         _16 = copy _1;
-          StorageDead(_17);
--         _15 = opaque::<u16>(move _16) -> [return: bb3, unwind unreachable];
-+         _15 = opaque::<u16>(copy _1) -> [return: bb3, unwind unreachable];
+          StorageLive(_18);
+-         _18 = move _14;
+-         _17 = move _18 as u16 (Transmute);
++         _18 = copy _14;
++         _17 = copy _1;
+          StorageDead(_18);
+-         _16 = opaque::<u16>(move _17) -> [return: bb3, unwind unreachable];
++         _16 = opaque::<u16>(copy _1) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
+          StorageDead(_17);
           StorageDead(_16);
-          StorageDead(_15);
--         StorageLive(_18);
+-         StorageLive(_19);
 +         nop;
-          StorageLive(_19);
-          _19 = copy _1;
--         _18 = Option::<u16>::Some(move _19);
-+         _18 = Option::<u16>::Some(copy _1);
-          StorageDead(_19);
           StorageLive(_20);
+          _20 = copy _1;
+-         _19 = Option::<u16>::Some(move _20);
++         _19 = Option::<u16>::Some(copy _1);
+          StorageDead(_20);
           StorageLive(_21);
           StorageLive(_22);
-          _22 = copy _18;
--         _21 = move _22 as u32 (Transmute);
-+         _21 = copy _18 as u32 (Transmute);
-          StorageDead(_22);
-          _20 = opaque::<u32>(move _21) -> [return: bb4, unwind unreachable];
+          StorageLive(_23);
+          _23 = copy _19;
+-         _22 = move _23 as u32 (Transmute);
++         _22 = copy _19 as u32 (Transmute);
+          StorageDead(_23);
+          _21 = opaque::<u32>(move _22) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
+          StorageDead(_22);
           StorageDead(_21);
-          StorageDead(_20);
-          StorageLive(_23);
           StorageLive(_24);
-          _24 = copy _1;
--         _23 = MyId(move _24);
-+         _23 = copy _2;
-          StorageDead(_24);
           StorageLive(_25);
+          _25 = copy _1;
+-         _24 = MyId(move _25);
++         _24 = copy _3;
+          StorageDead(_25);
           StorageLive(_26);
           StorageLive(_27);
--         _27 = move _23;
--         _26 = move _27 as i16 (Transmute);
-+         _27 = copy _2;
-+         _26 = copy _1 as i16 (Transmute);
-          StorageDead(_27);
-          _25 = opaque::<i16>(move _26) -> [return: bb5, unwind unreachable];
+          StorageLive(_28);
+-         _28 = move _24;
+-         _27 = move _28 as i16 (Transmute);
++         _28 = copy _3;
++         _27 = copy _1 as i16 (Transmute);
+          StorageDead(_28);
+          _26 = opaque::<i16>(move _27) -> [return: bb5, unwind unreachable];
       }
   
       bb5: {
+          StorageDead(_27);
           StorageDead(_26);
-          StorageDead(_25);
--         StorageLive(_28);
+-         StorageLive(_29);
 +         nop;
-          StorageLive(_29);
-          _29 = copy _1;
           StorageLive(_30);
           _30 = copy _1;
--         _28 = Pair(move _29, move _30);
-+         _28 = Pair(copy _1, copy _1);
-          StorageDead(_30);
-          StorageDead(_29);
           StorageLive(_31);
+          _31 = copy _1;
+-         _29 = Pair(move _30, move _31);
++         _29 = Pair(copy _1, copy _1);
+          StorageDead(_31);
+          StorageDead(_30);
           StorageLive(_32);
           StorageLive(_33);
--         _33 = move _28;
--         _32 = move _33 as u32 (Transmute);
-+         _33 = copy _28;
-+         _32 = copy _28 as u32 (Transmute);
-          StorageDead(_33);
-          _31 = opaque::<u32>(move _32) -> [return: bb6, unwind unreachable];
+          StorageLive(_34);
+-         _34 = move _29;
+-         _33 = move _34 as u32 (Transmute);
++         _34 = copy _29;
++         _33 = copy _29 as u32 (Transmute);
+          StorageDead(_34);
+          _32 = opaque::<u32>(move _33) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
+          StorageDead(_33);
           StorageDead(_32);
-          StorageDead(_31);
-          StorageLive(_34);
           StorageLive(_35);
-          _35 = copy _1;
           StorageLive(_36);
           _36 = copy _1;
--         _34 = Pair(move _35, move _36);
-+         _34 = copy _28;
-          StorageDead(_36);
-          StorageDead(_35);
           StorageLive(_37);
+          _37 = copy _1;
+-         _35 = Pair(move _36, move _37);
++         _35 = copy _29;
+          StorageDead(_37);
+          StorageDead(_36);
           StorageLive(_38);
           StorageLive(_39);
--         _39 = move _34;
--         _38 = move _39 as u16 (Transmute);
-+         _39 = copy _28;
-+         _38 = copy _28 as u16 (Transmute);
-          StorageDead(_39);
-          _37 = opaque::<u16>(move _38) -> [return: bb7, unwind unreachable];
+          StorageLive(_40);
+-         _40 = move _35;
+-         _39 = move _40 as u16 (Transmute);
++         _40 = copy _29;
++         _39 = copy _29 as u16 (Transmute);
+          StorageDead(_40);
+          _38 = opaque::<u16>(move _39) -> [return: bb7, unwind unreachable];
       }
   
       bb7: {
+          StorageDead(_39);
           StorageDead(_38);
-          StorageDead(_37);
+-         StorageLive(_41);
++         nop;
+          StorageLive(_42);
+          _42 = copy _1;
+-         _41 = (move _42,);
++         _41 = (copy _1,);
+          StorageDead(_42);
+          StorageLive(_43);
+          StorageLive(_44);
+          StorageLive(_45);
+          _45 = copy _41;
+-         _44 = move _45 as u16 (Transmute);
++         _44 = copy _1;
+          StorageDead(_45);
+-         _43 = opaque::<u16>(move _44) -> [return: bb8, unwind unreachable];
++         _43 = opaque::<u16>(copy _1) -> [return: bb8, unwind unreachable];
+      }
+  
+      bb8: {
+          StorageDead(_44);
+          StorageDead(_43);
+-         StorageLive(_46);
++         nop;
+          StorageLive(_47);
+          _47 = copy _1;
+-         _46 = [move _47];
++         _46 = [copy _1];
+          StorageDead(_47);
+          StorageLive(_48);
+          StorageLive(_49);
+          StorageLive(_50);
+          _50 = copy _46;
+-         _49 = move _50 as u16 (Transmute);
++         _49 = copy _1;
+          StorageDead(_50);
+-         _48 = opaque::<u16>(move _49) -> [return: bb9, unwind unreachable];
++         _48 = opaque::<u16>(copy _1) -> [return: bb9, unwind unreachable];
+      }
+  
+      bb9: {
+          StorageDead(_49);
+          StorageDead(_48);
+-         StorageLive(_51);
++         nop;
+          StorageLive(_52);
+          _52 = copy _2;
+          StorageLive(_53);
+-         _53 = ();
+-         _51 = *const i32 from (move _52, move _53);
++         _53 = const ();
++         _51 = *const i32 from (copy _2, const ());
+          StorageDead(_53);
+          StorageDead(_52);
+          StorageLive(_54);
+          StorageLive(_55);
+          StorageLive(_56);
+          _56 = copy _51;
+-         _55 = move _56 as *const u8 (Transmute);
++         _55 = copy _2;
+          StorageDead(_56);
+-         _54 = opaque::<*const u8>(move _55) -> [return: bb10, unwind unreachable];
++         _54 = opaque::<*const u8>(copy _2) -> [return: bb10, unwind unreachable];
+      }
+  
+      bb10: {
+          StorageDead(_55);
+          StorageDead(_54);
           _0 = const ();
-          StorageDead(_34);
--         StorageDead(_28);
+-         StorageDead(_51);
+-         StorageDead(_46);
+-         StorageDead(_41);
 +         nop;
-          StorageDead(_23);
--         StorageDead(_18);
--         StorageDead(_13);
--         StorageDead(_7);
--         StorageDead(_2);
++         nop;
++         nop;
+          StorageDead(_35);
+-         StorageDead(_29);
++         nop;
+          StorageDead(_24);
+-         StorageDead(_19);
+-         StorageDead(_14);
+-         StorageDead(_8);
+-         StorageDead(_3);
 +         nop;
 +         nop;
 +         nop;
diff --git a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff
index b6b6b1627b7..3119a93fb89 100644
--- a/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.aggregate_struct_then_transmute.GVN.panic-unwind.diff
@@ -1,61 +1,87 @@
 - // MIR for `aggregate_struct_then_transmute` before GVN
 + // MIR for `aggregate_struct_then_transmute` after GVN
   
-  fn aggregate_struct_then_transmute(_1: u16) -> () {
+  fn aggregate_struct_then_transmute(_1: u16, _2: *const u8) -> () {
       debug id => _1;
+      debug thin => _2;
       let mut _0: ();
-      let _2: MyId;
-      let mut _3: u16;
-      let _4: ();
-      let mut _5: u16;
-      let mut _6: MyId;
-      let mut _8: u16;
-      let mut _9: std::marker::PhantomData<std::string::String>;
-      let _10: ();
-      let mut _11: u16;
-      let mut _12: TypedId<std::string::String>;
-      let mut _14: u16;
-      let _15: ();
-      let mut _16: u16;
-      let mut _17: std::result::Result<Never, u16>;
-      let mut _19: u16;
-      let _20: ();
-      let mut _21: u32;
-      let mut _22: std::option::Option<u16>;
-      let mut _24: u16;
-      let _25: ();
-      let mut _26: i16;
-      let mut _27: MyId;
-      let mut _29: u16;
+      let _3: MyId;
+      let mut _4: u16;
+      let _5: ();
+      let mut _6: u16;
+      let mut _7: MyId;
+      let mut _9: u16;
+      let mut _10: std::marker::PhantomData<std::string::String>;
+      let _11: ();
+      let mut _12: u16;
+      let mut _13: TypedId<std::string::String>;
+      let mut _15: u16;
+      let _16: ();
+      let mut _17: u16;
+      let mut _18: std::result::Result<Never, u16>;
+      let mut _20: u16;
+      let _21: ();
+      let mut _22: u32;
+      let mut _23: std::option::Option<u16>;
+      let mut _25: u16;
+      let _26: ();
+      let mut _27: i16;
+      let mut _28: MyId;
       let mut _30: u16;
-      let _31: ();
-      let mut _32: u32;
-      let mut _33: aggregate_struct_then_transmute::Pair;
-      let mut _35: u16;
+      let mut _31: u16;
+      let _32: ();
+      let mut _33: u32;
+      let mut _34: aggregate_struct_then_transmute::Pair;
       let mut _36: u16;
-      let _37: ();
-      let mut _38: u16;
-      let mut _39: aggregate_struct_then_transmute::Pair;
+      let mut _37: u16;
+      let _38: ();
+      let mut _39: u16;
+      let mut _40: aggregate_struct_then_transmute::Pair;
+      let mut _42: u16;
+      let _43: ();
+      let mut _44: u16;
+      let mut _45: (u16,);
+      let mut _47: u16;
+      let _48: ();
+      let mut _49: u16;
+      let mut _50: [u16; 1];
+      let mut _52: *const u8;
+      let mut _53: ();
+      let _54: ();
+      let mut _55: *const u8;
+      let mut _56: *const i32;
       scope 1 {
-          debug a => _2;
-          let _7: TypedId<std::string::String>;
+          debug a => _3;
+          let _8: TypedId<std::string::String>;
           scope 2 {
-              debug b => _7;
-              let _13: std::result::Result<Never, u16>;
+              debug b => _8;
+              let _14: std::result::Result<Never, u16>;
               scope 3 {
-                  debug c => _13;
-                  let _18: std::option::Option<u16>;
+                  debug c => _14;
+                  let _19: std::option::Option<u16>;
                   scope 4 {
-                      debug d => _18;
-                      let _23: MyId;
+                      debug d => _19;
+                      let _24: MyId;
                       scope 5 {
-                          debug e => _23;
-                          let _28: aggregate_struct_then_transmute::Pair;
+                          debug e => _24;
+                          let _29: aggregate_struct_then_transmute::Pair;
                           scope 6 {
-                              debug f => _28;
-                              let _34: aggregate_struct_then_transmute::Pair;
+                              debug f => _29;
+                              let _35: aggregate_struct_then_transmute::Pair;
                               scope 7 {
-                                  debug g => _34;
+                                  debug g => _35;
+                                  let _41: (u16,);
+                                  scope 8 {
+                                      debug h => _41;
+                                      let _46: [u16; 1];
+                                      scope 9 {
+                                          debug i => _46;
+                                          let _51: *const i32;
+                                          scope 10 {
+                                              debug j => _51;
+                                          }
+                                      }
+                                  }
                               }
                           }
                       }
@@ -65,172 +91,245 @@
       }
   
       bb0: {
--         StorageLive(_2);
+-         StorageLive(_3);
 +         nop;
-          StorageLive(_3);
-          _3 = copy _1;
--         _2 = MyId(move _3);
-+         _2 = MyId(copy _1);
-          StorageDead(_3);
           StorageLive(_4);
+          _4 = copy _1;
+-         _3 = MyId(move _4);
++         _3 = MyId(copy _1);
+          StorageDead(_4);
           StorageLive(_5);
           StorageLive(_6);
--         _6 = move _2;
--         _5 = move _6 as u16 (Transmute);
-+         _6 = copy _2;
-+         _5 = copy _1;
-          StorageDead(_6);
--         _4 = opaque::<u16>(move _5) -> [return: bb1, unwind continue];
-+         _4 = opaque::<u16>(copy _1) -> [return: bb1, unwind continue];
+          StorageLive(_7);
+-         _7 = move _3;
+-         _6 = move _7 as u16 (Transmute);
++         _7 = copy _3;
++         _6 = copy _1;
+          StorageDead(_7);
+-         _5 = opaque::<u16>(move _6) -> [return: bb1, unwind continue];
++         _5 = opaque::<u16>(copy _1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
+          StorageDead(_6);
           StorageDead(_5);
-          StorageDead(_4);
--         StorageLive(_7);
+-         StorageLive(_8);
 +         nop;
-          StorageLive(_8);
-          _8 = copy _1;
           StorageLive(_9);
--         _9 = PhantomData::<String>;
--         _7 = TypedId::<String>(move _8, move _9);
-+         _9 = const PhantomData::<String>;
-+         _7 = TypedId::<String>(copy _1, const PhantomData::<String>);
-          StorageDead(_9);
-          StorageDead(_8);
+          _9 = copy _1;
           StorageLive(_10);
+-         _10 = PhantomData::<String>;
+-         _8 = TypedId::<String>(move _9, move _10);
++         _10 = const PhantomData::<String>;
++         _8 = TypedId::<String>(copy _1, const PhantomData::<String>);
+          StorageDead(_10);
+          StorageDead(_9);
           StorageLive(_11);
           StorageLive(_12);
--         _12 = move _7;
--         _11 = move _12 as u16 (Transmute);
-+         _12 = copy _7;
-+         _11 = copy _1;
-          StorageDead(_12);
--         _10 = opaque::<u16>(move _11) -> [return: bb2, unwind continue];
-+         _10 = opaque::<u16>(copy _1) -> [return: bb2, unwind continue];
+          StorageLive(_13);
+-         _13 = move _8;
+-         _12 = move _13 as u16 (Transmute);
++         _13 = copy _8;
++         _12 = copy _1;
+          StorageDead(_13);
+-         _11 = opaque::<u16>(move _12) -> [return: bb2, unwind continue];
++         _11 = opaque::<u16>(copy _1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
+          StorageDead(_12);
           StorageDead(_11);
-          StorageDead(_10);
--         StorageLive(_13);
+-         StorageLive(_14);
 +         nop;
-          StorageLive(_14);
-          _14 = copy _1;
--         _13 = Result::<Never, u16>::Err(move _14);
-+         _13 = Result::<Never, u16>::Err(copy _1);
-          StorageDead(_14);
           StorageLive(_15);
+          _15 = copy _1;
+-         _14 = Result::<Never, u16>::Err(move _15);
++         _14 = Result::<Never, u16>::Err(copy _1);
+          StorageDead(_15);
           StorageLive(_16);
           StorageLive(_17);
--         _17 = move _13;
--         _16 = move _17 as u16 (Transmute);
-+         _17 = copy _13;
-+         _16 = copy _1;
-          StorageDead(_17);
--         _15 = opaque::<u16>(move _16) -> [return: bb3, unwind continue];
-+         _15 = opaque::<u16>(copy _1) -> [return: bb3, unwind continue];
+          StorageLive(_18);
+-         _18 = move _14;
+-         _17 = move _18 as u16 (Transmute);
++         _18 = copy _14;
++         _17 = copy _1;
+          StorageDead(_18);
+-         _16 = opaque::<u16>(move _17) -> [return: bb3, unwind continue];
++         _16 = opaque::<u16>(copy _1) -> [return: bb3, unwind continue];
       }
   
       bb3: {
+          StorageDead(_17);
           StorageDead(_16);
-          StorageDead(_15);
--         StorageLive(_18);
+-         StorageLive(_19);
 +         nop;
-          StorageLive(_19);
-          _19 = copy _1;
--         _18 = Option::<u16>::Some(move _19);
-+         _18 = Option::<u16>::Some(copy _1);
-          StorageDead(_19);
           StorageLive(_20);
+          _20 = copy _1;
+-         _19 = Option::<u16>::Some(move _20);
++         _19 = Option::<u16>::Some(copy _1);
+          StorageDead(_20);
           StorageLive(_21);
           StorageLive(_22);
-          _22 = copy _18;
--         _21 = move _22 as u32 (Transmute);
-+         _21 = copy _18 as u32 (Transmute);
-          StorageDead(_22);
-          _20 = opaque::<u32>(move _21) -> [return: bb4, unwind continue];
+          StorageLive(_23);
+          _23 = copy _19;
+-         _22 = move _23 as u32 (Transmute);
++         _22 = copy _19 as u32 (Transmute);
+          StorageDead(_23);
+          _21 = opaque::<u32>(move _22) -> [return: bb4, unwind continue];
       }
   
       bb4: {
+          StorageDead(_22);
           StorageDead(_21);
-          StorageDead(_20);
-          StorageLive(_23);
           StorageLive(_24);
-          _24 = copy _1;
--         _23 = MyId(move _24);
-+         _23 = copy _2;
-          StorageDead(_24);
           StorageLive(_25);
+          _25 = copy _1;
+-         _24 = MyId(move _25);
++         _24 = copy _3;
+          StorageDead(_25);
           StorageLive(_26);
           StorageLive(_27);
--         _27 = move _23;
--         _26 = move _27 as i16 (Transmute);
-+         _27 = copy _2;
-+         _26 = copy _1 as i16 (Transmute);
-          StorageDead(_27);
-          _25 = opaque::<i16>(move _26) -> [return: bb5, unwind continue];
+          StorageLive(_28);
+-         _28 = move _24;
+-         _27 = move _28 as i16 (Transmute);
++         _28 = copy _3;
++         _27 = copy _1 as i16 (Transmute);
+          StorageDead(_28);
+          _26 = opaque::<i16>(move _27) -> [return: bb5, unwind continue];
       }
   
       bb5: {
+          StorageDead(_27);
           StorageDead(_26);
-          StorageDead(_25);
--         StorageLive(_28);
+-         StorageLive(_29);
 +         nop;
-          StorageLive(_29);
-          _29 = copy _1;
           StorageLive(_30);
           _30 = copy _1;
--         _28 = Pair(move _29, move _30);
-+         _28 = Pair(copy _1, copy _1);
-          StorageDead(_30);
-          StorageDead(_29);
           StorageLive(_31);
+          _31 = copy _1;
+-         _29 = Pair(move _30, move _31);
++         _29 = Pair(copy _1, copy _1);
+          StorageDead(_31);
+          StorageDead(_30);
           StorageLive(_32);
           StorageLive(_33);
--         _33 = move _28;
--         _32 = move _33 as u32 (Transmute);
-+         _33 = copy _28;
-+         _32 = copy _28 as u32 (Transmute);
-          StorageDead(_33);
-          _31 = opaque::<u32>(move _32) -> [return: bb6, unwind continue];
+          StorageLive(_34);
+-         _34 = move _29;
+-         _33 = move _34 as u32 (Transmute);
++         _34 = copy _29;
++         _33 = copy _29 as u32 (Transmute);
+          StorageDead(_34);
+          _32 = opaque::<u32>(move _33) -> [return: bb6, unwind continue];
       }
   
       bb6: {
+          StorageDead(_33);
           StorageDead(_32);
-          StorageDead(_31);
-          StorageLive(_34);
           StorageLive(_35);
-          _35 = copy _1;
           StorageLive(_36);
           _36 = copy _1;
--         _34 = Pair(move _35, move _36);
-+         _34 = copy _28;
-          StorageDead(_36);
-          StorageDead(_35);
           StorageLive(_37);
+          _37 = copy _1;
+-         _35 = Pair(move _36, move _37);
++         _35 = copy _29;
+          StorageDead(_37);
+          StorageDead(_36);
           StorageLive(_38);
           StorageLive(_39);
--         _39 = move _34;
--         _38 = move _39 as u16 (Transmute);
-+         _39 = copy _28;
-+         _38 = copy _28 as u16 (Transmute);
-          StorageDead(_39);
-          _37 = opaque::<u16>(move _38) -> [return: bb7, unwind continue];
+          StorageLive(_40);
+-         _40 = move _35;
+-         _39 = move _40 as u16 (Transmute);
++         _40 = copy _29;
++         _39 = copy _29 as u16 (Transmute);
+          StorageDead(_40);
+          _38 = opaque::<u16>(move _39) -> [return: bb7, unwind continue];
       }
   
       bb7: {
+          StorageDead(_39);
           StorageDead(_38);
-          StorageDead(_37);
+-         StorageLive(_41);
++         nop;
+          StorageLive(_42);
+          _42 = copy _1;
+-         _41 = (move _42,);
++         _41 = (copy _1,);
+          StorageDead(_42);
+          StorageLive(_43);
+          StorageLive(_44);
+          StorageLive(_45);
+          _45 = copy _41;
+-         _44 = move _45 as u16 (Transmute);
++         _44 = copy _1;
+          StorageDead(_45);
+-         _43 = opaque::<u16>(move _44) -> [return: bb8, unwind continue];
++         _43 = opaque::<u16>(copy _1) -> [return: bb8, unwind continue];
+      }
+  
+      bb8: {
+          StorageDead(_44);
+          StorageDead(_43);
+-         StorageLive(_46);
++         nop;
+          StorageLive(_47);
+          _47 = copy _1;
+-         _46 = [move _47];
++         _46 = [copy _1];
+          StorageDead(_47);
+          StorageLive(_48);
+          StorageLive(_49);
+          StorageLive(_50);
+          _50 = copy _46;
+-         _49 = move _50 as u16 (Transmute);
++         _49 = copy _1;
+          StorageDead(_50);
+-         _48 = opaque::<u16>(move _49) -> [return: bb9, unwind continue];
++         _48 = opaque::<u16>(copy _1) -> [return: bb9, unwind continue];
+      }
+  
+      bb9: {
+          StorageDead(_49);
+          StorageDead(_48);
+-         StorageLive(_51);
++         nop;
+          StorageLive(_52);
+          _52 = copy _2;
+          StorageLive(_53);
+-         _53 = ();
+-         _51 = *const i32 from (move _52, move _53);
++         _53 = const ();
++         _51 = *const i32 from (copy _2, const ());
+          StorageDead(_53);
+          StorageDead(_52);
+          StorageLive(_54);
+          StorageLive(_55);
+          StorageLive(_56);
+          _56 = copy _51;
+-         _55 = move _56 as *const u8 (Transmute);
++         _55 = copy _2;
+          StorageDead(_56);
+-         _54 = opaque::<*const u8>(move _55) -> [return: bb10, unwind continue];
++         _54 = opaque::<*const u8>(copy _2) -> [return: bb10, unwind continue];
+      }
+  
+      bb10: {
+          StorageDead(_55);
+          StorageDead(_54);
           _0 = const ();
-          StorageDead(_34);
--         StorageDead(_28);
+-         StorageDead(_51);
+-         StorageDead(_46);
+-         StorageDead(_41);
 +         nop;
-          StorageDead(_23);
--         StorageDead(_18);
--         StorageDead(_13);
--         StorageDead(_7);
--         StorageDead(_2);
++         nop;
++         nop;
+          StorageDead(_35);
+-         StorageDead(_29);
++         nop;
+          StorageDead(_24);
+-         StorageDead(_19);
+-         StorageDead(_14);
+-         StorageDead(_8);
+-         StorageDead(_3);
 +         nop;
 +         nop;
 +         nop;
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 17357fed5a5..c895a579259 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -933,7 +933,7 @@ fn cast_pointer_eq(p1: *mut u8, p2: *mut u32, p3: *mut u32, p4: *mut [u32]) {
     // CHECK: _0 = const ();
 }
 
-unsafe fn aggregate_struct_then_transmute(id: u16) {
+unsafe fn aggregate_struct_then_transmute(id: u16, thin: *const u8) {
     // CHECK: opaque::<u16>(copy _1)
     let a = MyId(id);
     opaque(std::intrinsics::transmute::<_, u16>(a));
@@ -969,6 +969,18 @@ unsafe fn aggregate_struct_then_transmute(id: u16) {
     // CHECK: opaque::<u16>(move [[TEMP]])
     let g = Pair(id, id);
     opaque(std::intrinsics::transmute_unchecked::<_, u16>(g));
+
+    // CHECK: opaque::<u16>(copy _1)
+    let h = (id,);
+    opaque(std::intrinsics::transmute::<_, u16>(h));
+
+    // CHECK: opaque::<u16>(copy _1)
+    let i = [id];
+    opaque(std::intrinsics::transmute::<_, u16>(i));
+
+    // CHECK: opaque::<*const u8>(copy _2)
+    let j: *const i32 = std::intrinsics::aggregate_raw_ptr(thin, ());
+    opaque(std::intrinsics::transmute::<_, *const u8>(j));
 }
 
 unsafe fn transmute_then_transmute_again(a: u32, c: char) {