about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2023-04-15 16:41:57 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2023-09-06 15:52:06 +0000
commit74a967bcec51461b189048c1cc7fdcc684efb0de (patch)
tree843623dde6d9d69dd03fa038b93314e2f3dd3868
parent7ef555d84ab0f59ce9ee2199e6849824d9c16a63 (diff)
downloadrust-74a967bcec51461b189048c1cc7fdcc684efb0de.tar.gz
rust-74a967bcec51461b189048c1cc7fdcc684efb0de.zip
Support a few more rvalues.
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs5
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs83
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff76
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff72
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff72
-rw-r--r--tests/mir-opt/dataflow-const-prop/offset_of.rs49
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff18
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.rs63
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff22
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff20
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff15
-rw-r--r--tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff15
28 files changed, 835 insertions, 33 deletions
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index b16163edf14..9d99344d5bd 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -227,6 +227,11 @@ impl ScalarInt {
     }
 
     #[inline]
+    pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
+        Self::try_from_uint(i, tcx.data_layout.pointer_size)
+    }
+
+    #[inline]
     pub fn assert_bits(self, target_size: Size) -> u128 {
         self.to_bits(target_size).unwrap_or_else(|size| {
             bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index e713a6cf006..91bed82a634 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -193,47 +193,64 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         rvalue: &Rvalue<'tcx>,
         state: &mut State<Self::Value>,
     ) -> ValueOrPlace<Self::Value> {
-        match rvalue {
-            Rvalue::Cast(
-                kind @ (CastKind::IntToInt
-                | CastKind::FloatToInt
-                | CastKind::FloatToFloat
-                | CastKind::IntToFloat),
-                operand,
-                ty,
-            ) => match self.eval_operand(operand, state) {
-                FlatSet::Elem(op) => match kind {
-                    CastKind::IntToInt | CastKind::IntToFloat => {
-                        self.ecx.int_to_int_or_float(&op, *ty)
-                    }
-                    CastKind::FloatToInt | CastKind::FloatToFloat => {
-                        self.ecx.float_to_float_or_int(&op, *ty)
-                    }
-                    _ => unreachable!(),
+        let val = match rvalue {
+            Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => {
+                match self.eval_operand(operand, state) {
+                    FlatSet::Elem(op) => self
+                        .ecx
+                        .int_to_int_or_float(&op, *ty)
+                        .map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
+                    FlatSet::Bottom => FlatSet::Bottom,
+                    FlatSet::Top => FlatSet::Top,
                 }
-                .map(|result| ValueOrPlace::Value(self.wrap_immediate(result)))
-                .unwrap_or(ValueOrPlace::TOP),
-                _ => ValueOrPlace::TOP,
-            },
+            }
+            Rvalue::Cast(CastKind::FloatToInt | CastKind::FloatToFloat, operand, ty) => {
+                match self.eval_operand(operand, state) {
+                    FlatSet::Elem(op) => self
+                        .ecx
+                        .float_to_float_or_int(&op, *ty)
+                        .map_or(FlatSet::Top, |result| self.wrap_immediate(result)),
+                    FlatSet::Bottom => FlatSet::Bottom,
+                    FlatSet::Top => FlatSet::Top,
+                }
+            }
+            Rvalue::Cast(CastKind::Transmute, operand, _) => {
+                match self.eval_operand(operand, state) {
+                    FlatSet::Elem(op) => self.wrap_immediate(*op),
+                    FlatSet::Bottom => FlatSet::Bottom,
+                    FlatSet::Top => FlatSet::Top,
+                }
+            }
             Rvalue::BinaryOp(op, box (left, right)) => {
                 // Overflows must be ignored here.
                 let (val, _overflow) = self.binary_op(state, *op, left, right);
-                ValueOrPlace::Value(val)
+                val
             }
             Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) {
-                FlatSet::Elem(value) => self
-                    .ecx
-                    .unary_op(*op, &value)
-                    .map(|val| ValueOrPlace::Value(self.wrap_immty(val)))
-                    .unwrap_or(ValueOrPlace::Value(FlatSet::Top)),
-                FlatSet::Bottom => ValueOrPlace::Value(FlatSet::Bottom),
-                FlatSet::Top => ValueOrPlace::Value(FlatSet::Top),
+                FlatSet::Elem(value) => {
+                    self.ecx.unary_op(*op, &value).map_or(FlatSet::Top, |val| self.wrap_immty(val))
+                }
+                FlatSet::Bottom => FlatSet::Bottom,
+                FlatSet::Top => FlatSet::Top,
             },
-            Rvalue::Discriminant(place) => {
-                ValueOrPlace::Value(state.get_discr(place.as_ref(), self.map()))
+            Rvalue::NullaryOp(null_op, ty) => {
+                let Ok(layout) = self.tcx.layout_of(self.param_env.and(*ty)) else {
+                    return ValueOrPlace::Value(FlatSet::Top);
+                };
+                let val = match null_op {
+                    NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
+                    NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
+                    NullOp::OffsetOf(fields) => layout
+                        .offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index()))
+                        .bytes(),
+                    _ => return ValueOrPlace::Value(FlatSet::Top),
+                };
+                ScalarInt::try_from_target_usize(val, self.tcx).map_or(FlatSet::Top, FlatSet::Elem)
             }
-            _ => self.super_rvalue(rvalue, state),
-        }
+            Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
+            _ => return self.super_rvalue(rvalue, state),
+        };
+        ValueOrPlace::Value(val)
     }
 
     fn handle_constant(
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff
new file mode 100644
index 00000000000..c61414b6541
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff
@@ -0,0 +1,76 @@
+- // MIR for `concrete` before DataflowConstProp
++ // MIR for `concrete` after DataflowConstProp
+  
+  fn concrete() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug x => _1;
+          let _3: usize;
+          scope 2 {
+              debug y => _3;
+              let _5: usize;
+              scope 3 {
+                  debug z0 => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug z1 => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = OffsetOf(Alpha, [0]);
+-         _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
++         _2 = const 4_usize;
++         _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+-         _4 = OffsetOf(Alpha, [1]);
+-         _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
++         _4 = const 0_usize;
++         _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Alpha, [2, 0]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
++         _6 = const 2_usize;
++         _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Alpha, [2, 1]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
++         _8 = const 3_usize;
++         _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff
new file mode 100644
index 00000000000..0c3939a3456
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff
@@ -0,0 +1,76 @@
+- // MIR for `concrete` before DataflowConstProp
++ // MIR for `concrete` after DataflowConstProp
+  
+  fn concrete() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug x => _1;
+          let _3: usize;
+          scope 2 {
+              debug y => _3;
+              let _5: usize;
+              scope 3 {
+                  debug z0 => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug z1 => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = OffsetOf(Alpha, [0]);
+-         _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
++         _2 = const 4_usize;
++         _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+-         _4 = OffsetOf(Alpha, [1]);
+-         _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
++         _4 = const 0_usize;
++         _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Alpha, [2, 0]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
++         _6 = const 2_usize;
++         _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Alpha, [2, 1]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
++         _8 = const 3_usize;
++         _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff
new file mode 100644
index 00000000000..d54d4687060
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff
@@ -0,0 +1,72 @@
+- // MIR for `generic` before DataflowConstProp
++ // MIR for `generic` after DataflowConstProp
+  
+  fn generic() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug gx => _1;
+          let _3: usize;
+          scope 2 {
+              debug gy => _3;
+              let _5: usize;
+              scope 3 {
+                  debug dx => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug dy => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = OffsetOf(Gamma<T>, [0]);
+          _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = OffsetOf(Gamma<T>, [1]);
+          _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Delta<T>, [1]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
++         _6 = const 0_usize;
++         _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Delta<T>, [2]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
++         _8 = const 2_usize;
++         _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff
new file mode 100644
index 00000000000..6032a2274ef
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff
@@ -0,0 +1,72 @@
+- // MIR for `generic` before DataflowConstProp
++ // MIR for `generic` after DataflowConstProp
+  
+  fn generic() -> () {
+      let mut _0: ();
+      let _1: usize;
+      let mut _2: usize;
+      let mut _4: usize;
+      let mut _6: usize;
+      let mut _8: usize;
+      scope 1 {
+          debug gx => _1;
+          let _3: usize;
+          scope 2 {
+              debug gy => _3;
+              let _5: usize;
+              scope 3 {
+                  debug dx => _5;
+                  let _7: usize;
+                  scope 4 {
+                      debug dy => _7;
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = OffsetOf(Gamma<T>, [0]);
+          _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_2);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = OffsetOf(Gamma<T>, [1]);
+          _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_4);
+          StorageLive(_5);
+          StorageLive(_6);
+-         _6 = OffsetOf(Delta<T>, [1]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
++         _6 = const 0_usize;
++         _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          StorageDead(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+-         _8 = OffsetOf(Delta<T>, [2]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
++         _8 = const 2_usize;
++         _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];
+      }
+  
+      bb4: {
+          StorageDead(_8);
+          _0 = const ();
+          StorageDead(_7);
+          StorageDead(_5);
+          StorageDead(_3);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs
new file mode 100644
index 00000000000..ccc90790e52
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/offset_of.rs
@@ -0,0 +1,49 @@
+// unit-test: DataflowConstProp
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+
+#![feature(offset_of)]
+
+use std::marker::PhantomData;
+use std::mem::offset_of;
+
+struct Alpha {
+    x: u8,
+    y: u16,
+    z: Beta,
+}
+
+struct Beta(u8, u8);
+
+struct Gamma<T> {
+    x: u8,
+    y: u16,
+    _t: T,
+}
+
+#[repr(C)]
+struct Delta<T> {
+    _phantom: PhantomData<T>,
+    x: u8,
+    y: u16,
+}
+
+// EMIT_MIR offset_of.concrete.DataflowConstProp.diff
+fn concrete() {
+    let x = offset_of!(Alpha, x);
+    let y = offset_of!(Alpha, y);
+    let z0 = offset_of!(Alpha, z.0);
+    let z1 = offset_of!(Alpha, z.1);
+}
+
+// EMIT_MIR offset_of.generic.DataflowConstProp.diff
+fn generic<T>() {
+    let gx = offset_of!(Gamma<T>, x);
+    let gy = offset_of!(Gamma<T>, y);
+    let dx = offset_of!(Delta<T>, x);
+    let dy = offset_of!(Delta<T>, y);
+}
+
+fn main() {
+    concrete();
+    generic::<()>();
+}
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..52f096ac0e4
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `from_char` before DataflowConstProp
++ // MIR for `from_char` after DataflowConstProp
+  
+  fn from_char() -> i32 {
+      let mut _0: i32;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 'R' as i32 (Transmute);
++         _0 = const 82_i32;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..52f096ac0e4
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.from_char.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `from_char` before DataflowConstProp
++ // MIR for `from_char` after DataflowConstProp
+  
+  fn from_char() -> i32 {
+      let mut _0: i32;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 'R' as i32 (Transmute);
++         _0 = const 82_i32;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..3972eb209a1
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_bool` before DataflowConstProp
++ // MIR for `invalid_bool` after DataflowConstProp
+  
+  fn invalid_bool() -> bool {
+      let mut _0: bool;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const -1_i8 as bool (Transmute);
++         _0 = const {transmute(0xff): bool};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..3972eb209a1
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_bool.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_bool` before DataflowConstProp
++ // MIR for `invalid_bool` after DataflowConstProp
+  
+  fn invalid_bool() -> bool {
+      let mut _0: bool;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const -1_i8 as bool (Transmute);
++         _0 = const {transmute(0xff): bool};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..837dabde42a
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_char` before DataflowConstProp
++ // MIR for `invalid_char` after DataflowConstProp
+  
+  fn invalid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const _ as char (Transmute);
++         _0 = const {transmute(0x7fffffff): char};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..837dabde42a
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.invalid_char.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `invalid_char` before DataflowConstProp
++ // MIR for `invalid_char` after DataflowConstProp
+  
+  fn invalid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const _ as char (Transmute);
++         _0 = const {transmute(0x7fffffff): char};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..6091e169e8e
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.32bit.diff
@@ -0,0 +1,18 @@
+- // MIR for `less_as_i8` before DataflowConstProp
++ // MIR for `less_as_i8` after DataflowConstProp
+  
+  fn less_as_i8() -> i8 {
+      let mut _0: i8;
+      let mut _1: std::cmp::Ordering;
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = Less;
+          _0 = move _1 as i8 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..6091e169e8e
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.less_as_i8.DataflowConstProp.64bit.diff
@@ -0,0 +1,18 @@
+- // MIR for `less_as_i8` before DataflowConstProp
++ // MIR for `less_as_i8` after DataflowConstProp
+  
+  fn less_as_i8() -> i8 {
+      let mut _0: i8;
+      let mut _1: std::cmp::Ordering;
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = Less;
+          _0 = move _1 as i8 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs
new file mode 100644
index 00000000000..c25e33ab0b6
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.rs
@@ -0,0 +1,63 @@
+// unit-test: DataflowConstProp
+// compile-flags: -O --crate-type=lib
+// ignore-endian-big
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+use std::mem::transmute;
+
+// EMIT_MIR transmute.less_as_i8.DataflowConstProp.diff
+pub fn less_as_i8() -> i8 {
+    unsafe { transmute(std::cmp::Ordering::Less) }
+}
+
+// EMIT_MIR transmute.from_char.DataflowConstProp.diff
+pub fn from_char() -> i32 {
+    unsafe { transmute('R') }
+}
+
+// EMIT_MIR transmute.valid_char.DataflowConstProp.diff
+pub fn valid_char() -> char {
+    unsafe { transmute(0x52_u32) }
+}
+
+// EMIT_MIR transmute.invalid_char.DataflowConstProp.diff
+pub unsafe fn invalid_char() -> char {
+    unsafe { transmute(i32::MAX) }
+}
+
+// EMIT_MIR transmute.invalid_bool.DataflowConstProp.diff
+pub unsafe fn invalid_bool() -> bool {
+    unsafe { transmute(-1_i8) }
+}
+
+// EMIT_MIR transmute.undef_union_as_integer.DataflowConstProp.diff
+pub unsafe fn undef_union_as_integer() -> u32 {
+    union Union32 { value: u32, unit: () }
+    unsafe { transmute(Union32 { unit: () }) }
+}
+
+// EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff
+pub unsafe fn unreachable_direct() -> ! {
+    let x: Never = unsafe { transmute(()) };
+    match x {}
+}
+
+// EMIT_MIR transmute.unreachable_ref.DataflowConstProp.diff
+pub unsafe fn unreachable_ref() -> ! {
+    let x: &Never = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+// EMIT_MIR transmute.unreachable_mut.DataflowConstProp.diff
+pub unsafe fn unreachable_mut() -> ! {
+    let x: &mut Never = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+// EMIT_MIR transmute.unreachable_box.DataflowConstProp.diff
+pub unsafe fn unreachable_box() -> ! {
+    let x: Box<Never> = unsafe { transmute(1_usize) };
+    match *x {}
+}
+
+enum Never {}
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..fc0634b1f8f
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `undef_union_as_integer` before DataflowConstProp
++ // MIR for `undef_union_as_integer` after DataflowConstProp
+  
+  fn undef_union_as_integer() -> u32 {
+      let mut _0: u32;
+      let mut _1: undef_union_as_integer::Union32;
+      let mut _2: ();
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = Union32 { value: move _2 };
+          StorageDead(_2);
+          _0 = move _1 as u32 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..fc0634b1f8f
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `undef_union_as_integer` before DataflowConstProp
++ // MIR for `undef_union_as_integer` after DataflowConstProp
+  
+  fn undef_union_as_integer() -> u32 {
+      let mut _0: u32;
+      let mut _1: undef_union_as_integer::Union32;
+      let mut _2: ();
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = Union32 { value: move _2 };
+          StorageDead(_2);
+          _0 = move _1 as u32 (Transmute);
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..d0c298ba233
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_box` before DataflowConstProp
++ // MIR for `unreachable_box` after DataflowConstProp
+  
+  fn unreachable_box() -> ! {
+      let mut _0: !;
+      let _1: std::boxed::Box<Never>;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
++         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..d0c298ba233
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_box` before DataflowConstProp
++ // MIR for `unreachable_box` after DataflowConstProp
+  
+  fn unreachable_box() -> ! {
+      let mut _0: !;
+      let _1: std::boxed::Box<Never>;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
++         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..acbb5cd1bc7
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `unreachable_direct` before DataflowConstProp
++ // MIR for `unreachable_direct` after DataflowConstProp
+  
+  fn unreachable_direct() -> ! {
+      let mut _0: !;
+      let _1: Never;
+      let mut _2: ();
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = move _2 as Never (Transmute);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..acbb5cd1bc7
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff
@@ -0,0 +1,22 @@
+- // MIR for `unreachable_direct` before DataflowConstProp
++ // MIR for `unreachable_direct` after DataflowConstProp
+  
+  fn unreachable_direct() -> ! {
+      let mut _0: !;
+      let _1: Never;
+      let mut _2: ();
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          _2 = ();
+          _1 = move _2 as Never (Transmute);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..2ffaeea72db
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.32bit.diff
@@ -0,0 +1,24 @@
+- // MIR for `unreachable_mut` before DataflowConstProp
++ // MIR for `unreachable_mut` after DataflowConstProp
+  
+  fn unreachable_mut() -> ! {
+      let mut _0: !;
+      let _1: &mut Never;
+      let mut _2: &mut Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = const 1_usize as &mut Never (Transmute);
++         _2 = const {0x1 as &mut Never};
+          _1 = &mut (*_2);
+          StorageDead(_2);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..2ffaeea72db
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_mut.DataflowConstProp.64bit.diff
@@ -0,0 +1,24 @@
+- // MIR for `unreachable_mut` before DataflowConstProp
++ // MIR for `unreachable_mut` after DataflowConstProp
+  
+  fn unreachable_mut() -> ! {
+      let mut _0: !;
+      let _1: &mut Never;
+      let mut _2: &mut Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+-         _2 = const 1_usize as &mut Never (Transmute);
++         _2 = const {0x1 as &mut Never};
+          _1 = &mut (*_2);
+          StorageDead(_2);
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..31fcaafc5bc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.32bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_ref` before DataflowConstProp
++ // MIR for `unreachable_ref` after DataflowConstProp
+  
+  fn unreachable_ref() -> ! {
+      let mut _0: !;
+      let _1: &Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as &Never (Transmute);
++         _1 = const {0x1 as &Never};
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..31fcaafc5bc
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_ref.DataflowConstProp.64bit.diff
@@ -0,0 +1,20 @@
+- // MIR for `unreachable_ref` before DataflowConstProp
++ // MIR for `unreachable_ref` after DataflowConstProp
+  
+  fn unreachable_ref() -> ! {
+      let mut _0: !;
+      let _1: &Never;
+      scope 1 {
+          debug x => _1;
+      }
+      scope 2 {
+      }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = const 1_usize as &Never (Transmute);
++         _1 = const {0x1 as &Never};
+          unreachable;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
new file mode 100644
index 00000000000..402ef754a64
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.32bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `valid_char` before DataflowConstProp
++ // MIR for `valid_char` after DataflowConstProp
+  
+  fn valid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 82_u32 as char (Transmute);
++         _0 = const 'R';
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
new file mode 100644
index 00000000000..402ef754a64
--- /dev/null
+++ b/tests/mir-opt/dataflow-const-prop/transmute.valid_char.DataflowConstProp.64bit.diff
@@ -0,0 +1,15 @@
+- // MIR for `valid_char` before DataflowConstProp
++ // MIR for `valid_char` after DataflowConstProp
+  
+  fn valid_char() -> char {
+      let mut _0: char;
+      scope 1 {
+      }
+  
+      bb0: {
+-         _0 = const 82_u32 as char (Transmute);
++         _0 = const 'R';
+          return;
+      }
+  }
+