about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkadmin <julianknodt@gmail.com>2021-06-16 05:46:56 +0000
committerkadmin <julianknodt@gmail.com>2023-02-07 09:37:55 +0000
commit5d9f5145ac9ce07d79aeb75ad049cab957b0fb92 (patch)
tree39d1ba31d7bce333c72c25c6c3158f5cb5c02e16
parent3e97cef7e5696a57f1b528b2bf551a2e3721100d (diff)
downloadrust-5d9f5145ac9ce07d79aeb75ad049cab957b0fb92.tar.gz
rust-5d9f5145ac9ce07d79aeb75ad049cab957b0fb92.zip
Rm allocation in candidate
Instead of storing an extra array for discriminant values, create an allocation there and store
those in an allocation immediately.
-rw-r--r--compiler/rustc_mir/src/transform/large_enums.rs278
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs283
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs3
-rw-r--r--tests/codegen/consts.rs2
-rw-r--r--tests/codegen/function-arguments.rs2
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff55
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff55
-rw-r--r--tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff35
-rw-r--r--tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff35
-rw-r--r--tests/mir-opt/enum_opt.rs79
-rw-r--r--tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff46
-rw-r--r--tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff46
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff54
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff54
14 files changed, 746 insertions, 281 deletions
diff --git a/compiler/rustc_mir/src/transform/large_enums.rs b/compiler/rustc_mir/src/transform/large_enums.rs
deleted file mode 100644
index 51bf880313a..00000000000
--- a/compiler/rustc_mir/src/transform/large_enums.rs
+++ /dev/null
@@ -1,278 +0,0 @@
-use crate::transform::MirPass;
-use rustc_data_structures::stable_map::FxHashMap;
-use rustc_middle::mir::*;
-use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt};
-use rustc_span::def_id::DefId;
-use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants};
-use std::array::IntoIter;
-
-/// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
-/// enough discrepanc between them
-pub struct EnumSizeOpt<const DISCREPANCY: u64>;
-
-impl<'tcx, const D: u64> MirPass<'tcx> for EnumSizeOpt<D> {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        self.optim(tcx, body);
-    }
-}
-
-impl<const D: u64> EnumSizeOpt<D> {
-    fn candidate<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-        body_did: DefId,
-    ) -> Option<(u64, Vec<Size>)> {
-        match ty.kind() {
-            ty::Adt(adt_def, _substs) if adt_def.is_enum() => {
-                let p_e = tcx.param_env(body_did);
-                let layout =
-                    if let Ok(layout) = tcx.layout_of(p_e.and(ty)) { layout } else { return None };
-                let variants = &layout.variants;
-                match variants {
-                    Variants::Single { .. } => None,
-                    Variants::Multiple { variants, .. } if variants.len() <= 1 => None,
-                    Variants::Multiple { tag_encoding, .. }
-                        if matches!(tag_encoding, TagEncoding::Niche { .. }) =>
-                    {
-                        None
-                    }
-                    Variants::Multiple { variants, .. } => {
-                        let min = variants.iter().map(|v| v.size).min().unwrap();
-                        let max = variants.iter().map(|v| v.size).max().unwrap();
-                        if max.bytes() - min.bytes() < D {
-                            return None;
-                        }
-                        let mut discr_sizes = vec![Size::ZERO; adt_def.discriminants(tcx).count()];
-                        for (var_idx, layout) in variants.iter_enumerated() {
-                            let disc_idx =
-                                adt_def.discriminant_for_variant(tcx, var_idx).val as usize;
-                            assert_eq!(discr_sizes[disc_idx], Size::ZERO);
-                            discr_sizes[disc_idx] = layout.size;
-                        }
-                        Some((variants.len() as u64, discr_sizes))
-                    }
-                }
-            }
-            _ => None,
-        }
-    }
-    fn optim(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let mut alloc_cache = FxHashMap::default();
-        let body_did = body.source.def_id();
-        let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for bb in bbs {
-            bb.expand_statements(|st| {
-                match &st.kind {
-                    StatementKind::Assign(box (
-                        lhs,
-                        Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
-                    )) => {
-                        let ty = lhs.ty(local_decls, tcx).ty;
-
-                        let source_info = st.source_info;
-                        let span = source_info.span;
-
-                        let (num_variants, sizes) =
-                            if let Some(cand) = Self::candidate(tcx, ty, body_did) {
-                                cand
-                            } else {
-                                return None;
-                            };
-                        let adt_def = ty.ty_adt_def().unwrap();
-                        let alloc = if let Some(alloc) = alloc_cache.get(ty) {
-                            alloc
-                        } else {
-                            let data_layout = tcx.data_layout();
-                            let ptr_sized_int = data_layout.ptr_sized_integer();
-                            let target_bytes = ptr_sized_int.size().bytes() as usize;
-                            let mut data = vec![0; target_bytes * num_variants as usize];
-                            let mut curr = 0;
-                            macro_rules! encode_store {
-                                ($endian: expr, $bytes: expr) => {
-                                    let bytes = match $endian {
-                                        rustc_target::abi::Endian::Little => $bytes.to_le_bytes(),
-                                        rustc_target::abi::Endian::Big => $bytes.to_be_bytes(),
-                                    };
-                                    for b in bytes {
-                                        data[curr] = b;
-                                        curr += 1;
-                                    }
-                                };
-                            }
-
-                            for sz in sizes {
-                                match ptr_sized_int {
-                                    rustc_target::abi::Integer::I32 => {
-                                        encode_store!(data_layout.endian, sz.bytes() as u32);
-                                    }
-                                    rustc_target::abi::Integer::I64 => {
-                                        encode_store!(data_layout.endian, sz.bytes());
-                                    }
-                                    _ => unreachable!(),
-                                };
-                            }
-                            let alloc = interpret::Allocation::from_bytes(
-                                data,
-                                tcx.data_layout.ptr_sized_integer().align(&tcx.data_layout).abi,
-                                Mutability::Not,
-                            );
-                            let alloc = tcx.intern_const_alloc(alloc);
-                            alloc_cache.insert(ty, alloc);
-                            // FIXME(jknodt) use entry API
-                            alloc_cache.get(ty).unwrap()
-                        };
-
-                        let tmp_ty = tcx.mk_ty(ty::Array(
-                            tcx.types.usize,
-                            Const::from_usize(tcx, num_variants),
-                        ));
-
-                        let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
-                        let store_live = Statement {
-                            source_info,
-                            kind: StatementKind::StorageLive(size_array_local),
-                        };
-
-                        let place = Place::from(size_array_local);
-                        let constant_vals = Constant {
-                            span,
-                            user_ty: None,
-                            literal: ConstantKind::Val(
-                                interpret::ConstValue::ByRef { alloc, offset: Size::ZERO },
-                                tmp_ty,
-                            ),
-                        };
-                        let rval = Rvalue::Use(Operand::Constant(box (constant_vals)));
-
-                        let const_assign = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (place, rval)),
-                        };
-
-                        let discr_place = Place::from(
-                            local_decls
-                                .push(LocalDecl::new(adt_def.repr.discr_type().to_ty(tcx), span)),
-                        );
-
-                        let store_discr = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                discr_place,
-                                Rvalue::Discriminant(*rhs),
-                            )),
-                        };
-
-                        let discr_cast_place =
-                            Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
-
-                        let cast_discr = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                discr_cast_place,
-                                Rvalue::Cast(
-                                    CastKind::Misc,
-                                    Operand::Copy(discr_place),
-                                    tcx.types.usize,
-                                ),
-                            )),
-                        };
-
-                        let size_place =
-                            Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
-
-                        let store_size = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                size_place,
-                                Rvalue::Use(Operand::Copy(Place {
-                                    local: size_array_local,
-                                    projection: tcx.intern_place_elems(&[PlaceElem::Index(
-                                        discr_cast_place.local,
-                                    )]),
-                                })),
-                            )),
-                        };
-
-                        let dst =
-                            Place::from(local_decls.push(LocalDecl::new(tcx.mk_mut_ptr(ty), span)));
-
-                        let dst_ptr = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                dst,
-                                Rvalue::AddressOf(Mutability::Mut, *lhs),
-                            )),
-                        };
-
-                        let dst_cast_ty = tcx.mk_mut_ptr(tcx.types.u8);
-                        let dst_cast_place =
-                            Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
-
-                        let dst_cast = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                dst_cast_place,
-                                Rvalue::Cast(CastKind::Misc, Operand::Copy(dst), dst_cast_ty),
-                            )),
-                        };
-
-                        let src =
-                            Place::from(local_decls.push(LocalDecl::new(tcx.mk_imm_ptr(ty), span)));
-
-                        let src_ptr = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                src,
-                                Rvalue::AddressOf(Mutability::Not, *rhs),
-                            )),
-                        };
-
-                        let src_cast_ty = tcx.mk_imm_ptr(tcx.types.u8);
-                        let src_cast_place =
-                            Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
-
-                        let src_cast = Statement {
-                            source_info,
-                            kind: StatementKind::Assign(box (
-                                src_cast_place,
-                                Rvalue::Cast(CastKind::Misc, Operand::Copy(src), src_cast_ty),
-                            )),
-                        };
-
-                        let copy_bytes = Statement {
-                            source_info,
-                            kind: StatementKind::CopyNonOverlapping(box CopyNonOverlapping {
-                                src: Operand::Copy(src_cast_place),
-                                dst: Operand::Copy(dst_cast_place),
-                                count: Operand::Copy(size_place),
-                            }),
-                        };
-
-                        let store_dead = Statement {
-                            source_info,
-                            kind: StatementKind::StorageDead(size_array_local),
-                        };
-                        let iter = IntoIter::new([
-                            store_live,
-                            const_assign,
-                            store_discr,
-                            cast_discr,
-                            store_size,
-                            dst_ptr,
-                            dst_cast,
-                            src_ptr,
-                            src_cast,
-                            copy_bytes,
-                            store_dead,
-                        ]);
-
-                        st.make_nop();
-                        Some(iter)
-                    }
-                    _ => return None,
-                }
-            });
-        }
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
new file mode 100644
index 00000000000..1919720de49
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -0,0 +1,283 @@
+use crate::rustc_middle::ty::util::IntTypeExt;
+use crate::MirPass;
+use rustc_data_structures::stable_map::FxHashMap;
+use rustc_middle::mir::interpret::AllocId;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, AdtDef, Const, ParamEnv, Ty, TyCtxt};
+use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants};
+
+/// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
+/// enough discrepancy between them.
+///
+/// i.e. If there is are two variants:
+/// ```
+/// enum Example {
+///   Small,
+///   Large([u32; 1024]),
+/// }
+/// ```
+/// Instead of emitting moves of the large variant,
+/// Perform a memcpy instead.
+/// Based off of [this HackMD](https://hackmd.io/@ft4bxUsFT5CEUBmRKYHr7w/rJM8BBPzD).
+pub struct EnumSizeOpt {
+    pub(crate) discrepancy: u64,
+}
+
+impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let sess = tcx.sess;
+        if (!sess.opts.debugging_opts.unsound_mir_opts) || sess.mir_opt_level() < 3 {
+            return;
+        }
+        self.optim(tcx, body);
+    }
+}
+
+impl EnumSizeOpt {
+    fn candidate<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+        alloc_cache: &mut FxHashMap<Ty<'tcx>, AllocId>,
+    ) -> Option<(AdtDef<'tcx>, usize, AllocId)> {
+        let adt_def = match ty.kind() {
+            ty::Adt(adt_def, _substs) if adt_def.is_enum() => adt_def,
+            _ => return None,
+        };
+        let layout = tcx.layout_of(param_env.and(ty)).ok()?;
+        let variants = match &layout.variants {
+            Variants::Single { .. } => return None,
+            Variants::Multiple { tag_encoding, .. }
+                if matches!(tag_encoding, TagEncoding::Niche { .. }) =>
+            {
+                return None;
+            }
+            Variants::Multiple { variants, .. } if variants.len() <= 1 => return None,
+            Variants::Multiple { variants, .. } => variants,
+        };
+        let min = variants.iter().map(|v| v.size()).min().unwrap();
+        let max = variants.iter().map(|v| v.size()).max().unwrap();
+        if max.bytes() - min.bytes() < self.discrepancy {
+            return None;
+        }
+
+        let num_discrs = adt_def.discriminants(tcx).count();
+        if variants.iter_enumerated().any(|(var_idx, _)| {
+            let discr_for_var = adt_def.discriminant_for_variant(tcx, var_idx).val;
+            (discr_for_var > usize::MAX as u128) || (discr_for_var as usize >= num_discrs)
+        }) {
+            return None;
+        }
+        if let Some(alloc_id) = alloc_cache.get(&ty) {
+            return Some((*adt_def, num_discrs, *alloc_id));
+        }
+
+        let data_layout = tcx.data_layout();
+        let ptr_sized_int = data_layout.ptr_sized_integer();
+        let target_bytes = ptr_sized_int.size().bytes() as usize;
+        let mut data = vec![0; target_bytes * num_discrs];
+        macro_rules! encode_store {
+            ($curr_idx: expr, $endian: expr, $bytes: expr) => {
+                let bytes = match $endian {
+                    rustc_target::abi::Endian::Little => $bytes.to_le_bytes(),
+                    rustc_target::abi::Endian::Big => $bytes.to_be_bytes(),
+                };
+                for (i, b) in bytes.into_iter().enumerate() {
+                    data[$curr_idx + i] = b;
+                }
+            };
+        }
+
+        for (var_idx, layout) in variants.iter_enumerated() {
+            let curr_idx =
+                target_bytes * adt_def.discriminant_for_variant(tcx, var_idx).val as usize;
+            let sz = layout.size();
+            match ptr_sized_int {
+                rustc_target::abi::Integer::I32 => {
+                    encode_store!(curr_idx, data_layout.endian, sz.bytes() as u32);
+                }
+                rustc_target::abi::Integer::I64 => {
+                    encode_store!(curr_idx, data_layout.endian, sz.bytes());
+                }
+                _ => unreachable!(),
+            };
+        }
+        let alloc = interpret::Allocation::from_bytes(
+            data,
+            tcx.data_layout.ptr_sized_integer().align(&tcx.data_layout).abi,
+            Mutability::Not,
+        );
+        let alloc = tcx.create_memory_alloc(tcx.intern_const_alloc(alloc));
+        Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc)))
+    }
+    fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let mut alloc_cache = FxHashMap::default();
+        let body_did = body.source.def_id();
+        let param_env = tcx.param_env(body_did);
+        let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
+        for bb in bbs {
+            bb.expand_statements(|st| {
+                if let StatementKind::Assign(box (
+                    lhs,
+                    Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
+                )) = &st.kind
+                {
+                    let ty = lhs.ty(local_decls, tcx).ty;
+
+                    let source_info = st.source_info;
+                    let span = source_info.span;
+
+                    let (adt_def, num_variants, alloc_id) =
+                        self.candidate(tcx, param_env, ty, &mut alloc_cache)?;
+                    let alloc = tcx.global_alloc(alloc_id).unwrap_memory();
+
+                    let tmp_ty = tcx.mk_ty(ty::Array(
+                        tcx.types.usize,
+                        Const::from_usize(tcx, num_variants as u64),
+                    ));
+
+                    let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
+                    let store_live = Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(size_array_local),
+                    };
+
+                    let place = Place::from(size_array_local);
+                    let constant_vals = Constant {
+                        span,
+                        user_ty: None,
+                        literal: ConstantKind::Val(
+                            interpret::ConstValue::ByRef { alloc, offset: Size::ZERO },
+                            tmp_ty,
+                        ),
+                    };
+                    let rval = Rvalue::Use(Operand::Constant(box (constant_vals)));
+
+                    let const_assign =
+                        Statement { source_info, kind: StatementKind::Assign(box (place, rval)) };
+
+                    let discr_place = Place::from(
+                        local_decls
+                            .push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)),
+                    );
+
+                    let store_discr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (discr_place, Rvalue::Discriminant(*rhs))),
+                    };
+
+                    let discr_cast_place =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
+
+                    let cast_discr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            discr_cast_place,
+                            Rvalue::Cast(
+                                CastKind::Misc,
+                                Operand::Copy(discr_place),
+                                tcx.types.usize,
+                            ),
+                        )),
+                    };
+
+                    let size_place =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
+
+                    let store_size = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            size_place,
+                            Rvalue::Use(Operand::Copy(Place {
+                                local: size_array_local,
+                                projection: tcx.intern_place_elems(&[PlaceElem::Index(
+                                    discr_cast_place.local,
+                                )]),
+                            })),
+                        )),
+                    };
+
+                    let dst =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.mk_mut_ptr(ty), span)));
+
+                    let dst_ptr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            dst,
+                            Rvalue::AddressOf(Mutability::Mut, *lhs),
+                        )),
+                    };
+
+                    let dst_cast_ty = tcx.mk_mut_ptr(tcx.types.u8);
+                    let dst_cast_place =
+                        Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
+
+                    let dst_cast = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            dst_cast_place,
+                            Rvalue::Cast(CastKind::Misc, Operand::Copy(dst), dst_cast_ty),
+                        )),
+                    };
+
+                    let src =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.mk_imm_ptr(ty), span)));
+
+                    let src_ptr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            src,
+                            Rvalue::AddressOf(Mutability::Not, *rhs),
+                        )),
+                    };
+
+                    let src_cast_ty = tcx.mk_imm_ptr(tcx.types.u8);
+                    let src_cast_place =
+                        Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
+
+                    let src_cast = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            src_cast_place,
+                            Rvalue::Cast(CastKind::Misc, Operand::Copy(src), src_cast_ty),
+                        )),
+                    };
+
+                    let copy_bytes = Statement {
+                        source_info,
+                        kind: StatementKind::CopyNonOverlapping(box CopyNonOverlapping {
+                            src: Operand::Copy(src_cast_place),
+                            dst: Operand::Copy(dst_cast_place),
+                            count: Operand::Copy(size_place),
+                        }),
+                    };
+
+                    let store_dead = Statement {
+                        source_info,
+                        kind: StatementKind::StorageDead(size_array_local),
+                    };
+                    let iter = [
+                        store_live,
+                        const_assign,
+                        store_discr,
+                        cast_discr,
+                        store_size,
+                        dst_ptr,
+                        dst_cast,
+                        src_ptr,
+                        src_cast,
+                        copy_bytes,
+                        store_dead,
+                    ]
+                    .into_iter();
+
+                    st.make_nop();
+                    Some(iter)
+                } else {
+                    None
+                }
+            });
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 00ec4b3e754..8cd268eb6ce 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -3,7 +3,6 @@
 #![feature(drain_filter)]
 #![feature(let_chains)]
 #![feature(let_else)]
-#![feature(entry_insert)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(never_type)]
@@ -75,6 +74,7 @@ mod function_item_references;
 mod generator;
 mod inline;
 mod instcombine;
+mod large_enums;
 mod lower_intrinsics;
 mod lower_slice_len;
 mod match_branches;
@@ -547,6 +547,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         tcx,
         body,
         &[
+            &large_enums::EnumSizeOpt { discrepancy: 128 },
             &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
             &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
             &unreachable_prop::UnreachablePropagation,
diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs
index 9d75356b03d..260d9de8670 100644
--- a/tests/codegen/consts.rs
+++ b/tests/codegen/consts.rs
@@ -1,4 +1,4 @@
-// compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0
+// compile-flags: -C no-prepopulate-passes
 // min-llvm-version: 14.0
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 020d9234e57..96dfde18683 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -1,4 +1,4 @@
-// compile-flags: -O -C no-prepopulate-passes -Zmir-opt-level=0
+// compile-flags: -O -C no-prepopulate-passes
 
 #![crate_type = "lib"]
 
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..d9923ec7cba
--- /dev/null
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
@@ -0,0 +1,55 @@
+- // MIR for `cand` before EnumSizeOpt
++ // MIR for `cand` after EnumSizeOpt
+  
+  fn cand() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:49:15: 49:15
+      let mut _1: Candidate;               // in scope 0 at $DIR/enum_opt.rs:50:7: 50:12
+      let mut _2: Candidate;               // in scope 0 at $DIR/enum_opt.rs:51:7: 51:34
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:51:24: 51:33
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _8: *mut Candidate;          // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _10: *const Candidate;       // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:50:7: 50:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:50:7: 50:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:50:15: 50:34
+          ((_1 as Small).0: u8) = const 1_u8; // scope 0 at $DIR/enum_opt.rs:50:15: 50:34
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:50:15: 50:34
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:51:24: 51:33
+          _3 = [const 1_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:51:24: 51:33
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          ((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:51:33: 51:34
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _4 = const [2_usize, 8196_usize]; // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _6 = _5 as usize (Misc);         // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _9 = _8 as *mut u8 (Misc);       // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _11 = _10 as *const u8 (Misc);   // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         copy_nonoverlapping(src=_11, dst=_9, count=_7); // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:51:33: 51:34
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:49:15: 52:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:52:1: 52:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:52:2: 52:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:49:1: 52:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..e79d2f67a83
--- /dev/null
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
@@ -0,0 +1,55 @@
+- // MIR for `cand` before EnumSizeOpt
++ // MIR for `cand` after EnumSizeOpt
+  
+  fn cand() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:49:15: 49:15
+      let mut _1: Candidate;               // in scope 0 at $DIR/enum_opt.rs:50:7: 50:12
+      let mut _2: Candidate;               // in scope 0 at $DIR/enum_opt.rs:51:7: 51:34
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:51:24: 51:33
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _8: *mut Candidate;          // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _10: *const Candidate;       // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:51:3: 51:34
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:50:7: 50:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:50:7: 50:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:50:15: 50:34
+          ((_1 as Small).0: u8) = const 1_u8; // scope 0 at $DIR/enum_opt.rs:50:15: 50:34
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:50:15: 50:34
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:51:24: 51:33
+          _3 = [const 1_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:51:24: 51:33
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          ((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:51:7: 51:34
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:51:33: 51:34
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _4 = const [2_usize, 8200_usize]; // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _6 = _5 as usize (Misc);         // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _9 = _8 as *mut u8 (Misc);       // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         _11 = _10 as *const u8 (Misc);   // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         copy_nonoverlapping(src=_11, dst=_9, count=_7); // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:51:3: 51:34
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:51:33: 51:34
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:49:15: 52:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:52:1: 52:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:52:2: 52:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:49:1: 52:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..d8b6a794015
--- /dev/null
+++ b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff
@@ -0,0 +1,35 @@
+- // MIR for `invalid` before EnumSizeOpt
++ // MIR for `invalid` after EnumSizeOpt
+  
+  fn invalid() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:55:18: 55:18
+      let mut _1: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:56:7: 56:12
+      let mut _2: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:57:7: 57:36
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:57:26: 57:35
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:56:7: 56:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:56:7: 56:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:56:15: 56:29
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:56:15: 56:29
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:57:26: 57:35
+          _3 = [const 0_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:57:26: 57:35
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          ((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:57:35: 57:36
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:57:3: 57:36
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:57:35: 57:36
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:55:18: 58:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:58:1: 58:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:58:2: 58:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:55:1: 58:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..d8b6a794015
--- /dev/null
+++ b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff
@@ -0,0 +1,35 @@
+- // MIR for `invalid` before EnumSizeOpt
++ // MIR for `invalid` after EnumSizeOpt
+  
+  fn invalid() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:55:18: 55:18
+      let mut _1: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:56:7: 56:12
+      let mut _2: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:57:7: 57:36
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:57:26: 57:35
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:56:7: 56:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:56:7: 56:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:56:15: 56:29
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:56:15: 56:29
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:57:26: 57:35
+          _3 = [const 0_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:57:26: 57:35
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          ((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:57:7: 57:36
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:57:35: 57:36
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:57:3: 57:36
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:57:35: 57:36
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:55:18: 58:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:58:1: 58:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:58:2: 58:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:55:1: 58:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs
new file mode 100644
index 00000000000..bc72c93da09
--- /dev/null
+++ b/tests/mir-opt/enum_opt.rs
@@ -0,0 +1,79 @@
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// compile-flags: -Zunsound-mir-opts -Zmir-opt-level=3
+#![feature(arbitrary_enum_discriminant, repr128)]
+
+// Tests that an enum with a variant with no data gets correctly transformed.
+pub enum NoData {
+  None,
+  Large([u64; 1024]),
+}
+
+// Tests that an enum with a variant with data that is a valid candidate gets transformed.
+pub enum Candidate {
+  Small(u8),
+  Large([u64; 1024]),
+}
+
+// Tests that an enum which has a discriminant much higher than the variant does not get
+// tformed.
+#[repr(u32)]
+pub enum InvalidIdxs {
+  A = 302,
+  Large([u64; 1024]),
+}
+
+// Tests that an enum with too high of a discriminant index (not in bounds of usize) does not
+// get tformed.
+#[repr(u128)]
+pub enum Truncatable {
+    A = 0,
+    B([u8; 1024]) = 1,
+    C([u8; 4096]) = 0x10000000000000001,
+}
+
+// Tests that an enum with discriminants in random order still gets tformed correctly.
+#[repr(u32)]
+pub enum RandOrderDiscr {
+  A = 13,
+  B([u8; 1024]) = 5,
+  C = 7,
+}
+
+// EMIT_MIR enum_opt.unin.EnumSizeOpt.diff
+pub fn unin() {
+  let mut a = NoData::None;
+  a = NoData::Large([1; 1024]);
+}
+
+// EMIT_MIR enum_opt.cand.EnumSizeOpt.diff
+pub fn cand() {
+  let mut a = Candidate::Small(1);
+  a = Candidate::Large([1; 1024]);
+}
+
+// EMIT_MIR enum_opt.invalid.EnumSizeOpt.diff
+pub fn invalid() {
+  let mut a = InvalidIdxs::A;
+  a = InvalidIdxs::Large([0; 1024]);
+}
+
+// EMIT_MIR enum_opt.trunc.EnumSizeOpt.diff
+pub fn trunc() {
+  let mut a = Truncatable::A;
+  a = Truncatable::B([0; 1024]);
+  a = Truncatable::C([0; 4096]);
+}
+
+pub fn rand_order() {
+  let mut a = RandOrderDiscr::A;
+  a = RandOrderDiscr::B([0; 1024]);
+  a = RandOrderDiscr::C;
+}
+
+pub fn main() {
+  unin();
+  cand();
+  invalid();
+  trunc();
+  rand_order();
+}
diff --git a/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..650c6695f3f
--- /dev/null
+++ b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff
@@ -0,0 +1,46 @@
+- // MIR for `trunc` before EnumSizeOpt
++ // MIR for `trunc` after EnumSizeOpt
+  
+  fn trunc() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:61:16: 61:16
+      let mut _1: Truncatable;             // in scope 0 at $DIR/enum_opt.rs:62:7: 62:12
+      let mut _2: Truncatable;             // in scope 0 at $DIR/enum_opt.rs:63:7: 63:32
+      let mut _3: [u8; 1024];              // in scope 0 at $DIR/enum_opt.rs:63:22: 63:31
+      let mut _4: Truncatable;             // in scope 0 at $DIR/enum_opt.rs:64:7: 64:32
+      let mut _5: [u8; 4096];              // in scope 0 at $DIR/enum_opt.rs:64:22: 64:31
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:62:7: 62:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:62:7: 62:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:62:15: 62:29
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:62:15: 62:29
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:63:22: 63:31
+          _3 = [const 0_u8; 1024];         // scope 1 at $DIR/enum_opt.rs:63:22: 63:31
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          ((_2 as B).0: [u8; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:63:31: 63:32
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:63:3: 63:32
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:63:31: 63:32
+          StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          StorageLive(_5);                 // scope 1 at $DIR/enum_opt.rs:64:22: 64:31
+          _5 = [const 0_u8; 4096];         // scope 1 at $DIR/enum_opt.rs:64:22: 64:31
+          Deinit(_4);                      // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          ((_4 as C).0: [u8; 4096]) = move _5; // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          discriminant(_4) = 2;            // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          StorageDead(_5);                 // scope 1 at $DIR/enum_opt.rs:64:31: 64:32
+          _1 = move _4;                    // scope 1 at $DIR/enum_opt.rs:64:3: 64:32
+          StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:64:31: 64:32
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:61:16: 65:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:65:1: 65:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:65:2: 65:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:61:1: 65:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..650c6695f3f
--- /dev/null
+++ b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff
@@ -0,0 +1,46 @@
+- // MIR for `trunc` before EnumSizeOpt
++ // MIR for `trunc` after EnumSizeOpt
+  
+  fn trunc() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:61:16: 61:16
+      let mut _1: Truncatable;             // in scope 0 at $DIR/enum_opt.rs:62:7: 62:12
+      let mut _2: Truncatable;             // in scope 0 at $DIR/enum_opt.rs:63:7: 63:32
+      let mut _3: [u8; 1024];              // in scope 0 at $DIR/enum_opt.rs:63:22: 63:31
+      let mut _4: Truncatable;             // in scope 0 at $DIR/enum_opt.rs:64:7: 64:32
+      let mut _5: [u8; 4096];              // in scope 0 at $DIR/enum_opt.rs:64:22: 64:31
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:62:7: 62:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:62:7: 62:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:62:15: 62:29
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:62:15: 62:29
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:63:22: 63:31
+          _3 = [const 0_u8; 1024];         // scope 1 at $DIR/enum_opt.rs:63:22: 63:31
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          ((_2 as B).0: [u8; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:63:7: 63:32
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:63:31: 63:32
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:63:3: 63:32
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:63:31: 63:32
+          StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          StorageLive(_5);                 // scope 1 at $DIR/enum_opt.rs:64:22: 64:31
+          _5 = [const 0_u8; 4096];         // scope 1 at $DIR/enum_opt.rs:64:22: 64:31
+          Deinit(_4);                      // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          ((_4 as C).0: [u8; 4096]) = move _5; // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          discriminant(_4) = 2;            // scope 1 at $DIR/enum_opt.rs:64:7: 64:32
+          StorageDead(_5);                 // scope 1 at $DIR/enum_opt.rs:64:31: 64:32
+          _1 = move _4;                    // scope 1 at $DIR/enum_opt.rs:64:3: 64:32
+          StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:64:31: 64:32
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:61:16: 65:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:65:1: 65:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:65:2: 65:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:61:1: 65:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..c034c127eca
--- /dev/null
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
@@ -0,0 +1,54 @@
+- // MIR for `unin` before EnumSizeOpt
++ // MIR for `unin` after EnumSizeOpt
+  
+  fn unin() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:43:15: 43:15
+      let mut _1: NoData;                  // in scope 0 at $DIR/enum_opt.rs:44:7: 44:12
+      let mut _2: NoData;                  // in scope 0 at $DIR/enum_opt.rs:45:7: 45:31
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:45:21: 45:30
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _8: *mut NoData;             // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _10: *const NoData;          // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:44:7: 44:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:44:7: 44:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:44:15: 44:27
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:44:15: 44:27
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:45:21: 45:30
+          _3 = [const 1_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:45:21: 45:30
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          ((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:45:30: 45:31
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _4 = const [4_usize, 8196_usize]; // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _6 = _5 as usize (Misc);         // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _9 = _8 as *mut u8 (Misc);       // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _11 = _10 as *const u8 (Misc);   // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         copy_nonoverlapping(src=_11, dst=_9, count=_7); // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:45:30: 45:31
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:43:15: 46:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:46:1: 46:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:46:2: 46:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:43:1: 46:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..9389c0f12a0
--- /dev/null
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
@@ -0,0 +1,54 @@
+- // MIR for `unin` before EnumSizeOpt
++ // MIR for `unin` after EnumSizeOpt
+  
+  fn unin() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/enum_opt.rs:43:15: 43:15
+      let mut _1: NoData;                  // in scope 0 at $DIR/enum_opt.rs:44:7: 44:12
+      let mut _2: NoData;                  // in scope 0 at $DIR/enum_opt.rs:45:7: 45:31
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:45:21: 45:30
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _8: *mut NoData;             // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _10: *const NoData;          // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:45:3: 45:31
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:44:7: 44:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:44:7: 44:12
+          Deinit(_1);                      // scope 0 at $DIR/enum_opt.rs:44:15: 44:27
+          discriminant(_1) = 0;            // scope 0 at $DIR/enum_opt.rs:44:15: 44:27
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:45:21: 45:30
+          _3 = [const 1_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:45:21: 45:30
+          Deinit(_2);                      // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          ((_2 as Large).0: [u64; 1024]) = move _3; // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          discriminant(_2) = 1;            // scope 1 at $DIR/enum_opt.rs:45:7: 45:31
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:45:30: 45:31
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _4 = const [8_usize, 8200_usize]; // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _6 = _5 as usize (Misc);         // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _9 = _8 as *mut u8 (Misc);       // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         _11 = _10 as *const u8 (Misc);   // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         copy_nonoverlapping(src=_11, dst=_9, count=_7); // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:45:3: 45:31
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:45:30: 45:31
+          _0 = const ();                   // scope 0 at $DIR/enum_opt.rs:43:15: 46:2
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:46:1: 46:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:46:2: 46:2
+      }
+  
+      bb1 (cleanup): {
+          resume;                          // scope 0 at $DIR/enum_opt.rs:43:1: 46:2
+      }
+  }
+