about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-07 09:47:23 +0000
committerbors <bors@rust-lang.org>2022-09-07 09:47:23 +0000
commite7c7aa7288559f8e5ea7ce3543ff946b09783628 (patch)
treeb6b3ea66cbdcee10e6be4da6dbeed49fd89f0b22
parent0568b0a3de4eb37bf187eb61a9f017ae0018ad8f (diff)
parenta0130e62ecc6d0b450c34b25843f89e1e3ff63f0 (diff)
downloadrust-e7c7aa7288559f8e5ea7ce3543ff946b09783628.tar.gz
rust-e7c7aa7288559f8e5ea7ce3543ff946b09783628.zip
Auto merge of #98332 - oli-obk:assume, r=wesleywiser
Lower the assume intrinsic to a MIR statement

This makes https://github.com/rust-lang/rust/pull/96862#issuecomment-1153739068 easier and will generally allow us to cheaply insert assume intrinsic calls in mir building.

r? rust-lang/wg-mir-opt
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs2
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs26
-rw-r--r--compiler/rustc_borrowck/src/lib.rs28
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs39
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs34
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs24
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs8
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs2
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs42
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs17
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs31
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs2
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs2
-rw-r--r--src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff26
-rw-r--r--src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff72
-rw-r--r--src/test/mir-opt/lower_intrinsics.rs23
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.ConstProp.diff146
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir124
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff103
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir73
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs11
37 files changed, 338 insertions, 570 deletions
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 816288eb50b..9f7a4d49989 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -391,7 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
             | mir::StatementKind::Retag { .. }
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::Coverage(..)
-            | mir::StatementKind::CopyNonOverlapping(..)
+            | mir::StatementKind::Intrinsic(..)
             | mir::StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index ec521b1cf0a..3157f861d93 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
+use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
 use rustc_middle::mir::{BorrowKind, Mutability, Operand};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::mir::{Statement, StatementKind};
@@ -63,23 +63,24 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
             StatementKind::FakeRead(box (_, _)) => {
                 // Only relevant for initialized/liveness/safety checks.
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+                self.consume_operand(location, op);
+            }
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
                 ref src,
                 ref dst,
                 ref count,
-            }) => {
+            })) => {
                 self.consume_operand(location, src);
                 self.consume_operand(location, dst);
                 self.consume_operand(location, count);
             }
-            StatementKind::Nop
+            // Only relevant for mir typeck
+            StatementKind::AscribeUserType(..)
+            // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::StorageLive(..) => {
-                // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
-                // to borrow check.
-            }
+            // Does not actually affect borrowck
+            | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     location,
@@ -88,7 +89,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                     LocalMutationIsAllowed::Yes,
                 );
             }
-            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+            StatementKind::Nop
+            | StatementKind::Retag { .. }
+            | StatementKind::Deinit(..)
+            | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
         }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 20c22575bd1..ec652f85217 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -26,8 +26,8 @@ use rustc_index::bit_set::ChunkedBitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::{
-    traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
-    PlaceRef, VarDebugInfoContents,
+    traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
+    Place, PlaceElem, PlaceRef, VarDebugInfoContents,
 };
 use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -591,22 +591,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ..
-            }) => {
-                span_bug!(
+            StatementKind::Intrinsic(box ref kind) => match kind {
+                NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+                NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
                     span,
                     "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
                 )
             }
-            StatementKind::Nop
+            // Only relevant for mir typeck
+            StatementKind::AscribeUserType(..)
+            // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::StorageLive(..) => {
-                // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
-                // to borrow check.
-            }
+            // Does not actually affect borrowck
+            | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     location,
@@ -616,7 +613,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
-            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+            StatementKind::Nop
+            | StatementKind::Retag { .. }
+            | StatementKind::Deinit(..)
+            | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
         }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a620c987052..fc0e95f30c9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1302,12 +1302,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     );
                 }
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ..
-            }) => span_bug!(
-                stmt.source_info.span,
-                "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
-            ),
+            StatementKind::Intrinsic(box ref kind) => match kind {
+                NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
+                NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
+                    stmt.source_info.span,
+                    "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
+                ),
+            },
             StatementKind::FakeRead(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index c412e451a03..2aa11ac2eea 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -794,20 +794,31 @@ fn codegen_stmt<'tcx>(
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
-        StatementKind::CopyNonOverlapping(inner) => {
-            let dst = codegen_operand(fx, &inner.dst);
-            let pointee = dst
-                .layout()
-                .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
-                .expect("Expected pointer");
-            let dst = dst.load_scalar(fx);
-            let src = codegen_operand(fx, &inner.src).load_scalar(fx);
-            let count = codegen_operand(fx, &inner.count).load_scalar(fx);
-            let elem_size: u64 = pointee.size.bytes();
-            let bytes =
-                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
-            fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
-        }
+        StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic {
+            // We ignore `assume` intrinsics, they are only useful for optimizations
+            NonDivergingIntrinsic::Assume(_) => {}
+            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+                src,
+                dst,
+                count,
+            }) => {
+                let dst = codegen_operand(fx, dst);
+                let pointee = dst
+                    .layout()
+                    .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
+                    .expect("Expected pointer");
+                let dst = dst.load_scalar(fx);
+                let src = codegen_operand(fx, src).load_scalar(fx);
+                let count = codegen_operand(fx, count).load_scalar(fx);
+                let elem_size: u64 = pointee.size.bytes();
+                let bytes = if elem_size != 1 {
+                    fx.bcx.ins().imul_imm(count, elem_size as i64)
+                } else {
+                    count
+                };
+                fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
+            }
+        },
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 9224f499339..0305341da78 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -536,9 +536,11 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         {
                             return None;
                         }
-                        StatementKind::CopyNonOverlapping(_) => {
-                            return None;
-                        } // conservative handling
+                        StatementKind::Intrinsic(ref intrinsic) => match **intrinsic {
+                            NonDivergingIntrinsic::CopyNonOverlapping(..) => return None,
+                            NonDivergingIntrinsic::Assume(..) => {}
+                        },
+                        // conservative handling
                         StatementKind::Assign(_)
                         | StatementKind::FakeRead(_)
                         | StatementKind::SetDiscriminant { .. }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 39e9e784a47..0cd9332a58b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -357,9 +357,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
     match intrinsic {
-        sym::assume => {
-            intrinsic_args!(fx, args => (_a); intrinsic);
-        }
         sym::likely | sym::unlikely => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 16aad07194d..6393dd9d634 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -77,10 +77,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
 
         let llval = match name {
-            sym::assume => {
-                bx.assume(args[0].immediate());
-                return;
-            }
             sym::abort => {
                 bx.abort();
                 return;
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index f452f29883f..1db0fb3a6f1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -1,4 +1,5 @@
 use rustc_middle::mir;
+use rustc_middle::mir::NonDivergingIntrinsic;
 
 use super::FunctionCx;
 use super::LocalRef;
@@ -73,11 +74,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
                 bx
             }
-            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
+            mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
+                let op_val = self.codegen_operand(&mut bx, op);
+                bx.assume(op_val.immediate());
+                bx
+            }
+            mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+                mir::CopyNonOverlapping { ref count, ref src, ref dst },
+            )) => {
                 let dst_val = self.codegen_operand(&mut bx, dst);
                 let src_val = self.codegen_operand(&mut bx, src);
                 let count = self.codegen_operand(&mut bx, count).immediate();
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index adda9639990..2f415a8c9c7 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
     interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
-    BinOp,
+    BinOp, NonDivergingIntrinsic,
 };
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -506,12 +506,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // These just return their argument
                 self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
             }
-            sym::assume => {
-                let cond = self.read_scalar(&args[0])?.to_bool()?;
-                if !cond {
-                    throw_ub_format!("`assume` intrinsic called with `false`");
-                }
-            }
             sym::raw_eq => {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
@@ -536,6 +530,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(true)
     }
 
+    pub(super) fn emulate_nondiverging_intrinsic(
+        &mut self,
+        intrinsic: &NonDivergingIntrinsic<'tcx>,
+    ) -> InterpResult<'tcx> {
+        match intrinsic {
+            NonDivergingIntrinsic::Assume(op) => {
+                let op = self.eval_operand(op, None)?;
+                let cond = self.read_scalar(&op)?.to_bool()?;
+                if !cond {
+                    throw_ub_format!("`assume` called with `false`");
+                }
+                Ok(())
+            }
+            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+                count,
+                src,
+                dst,
+            }) => {
+                let src = self.eval_operand(src, None)?;
+                let dst = self.eval_operand(dst, None)?;
+                let count = self.eval_operand(count, None)?;
+                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)
+            }
+        }
+    }
+
     pub fn exact_div(
         &mut self,
         a: &ImmTy<'tcx, M::Provenance>,
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 6b827149f50..c6e04cbfb6b 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -114,13 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 M::retag(self, *kind, &dest)?;
             }
 
-            // Call CopyNonOverlapping
-            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
-                let src = self.eval_operand(src, None)?;
-                let dst = self.eval_operand(dst, None)?;
-                let count = self.eval_operand(count, None)?;
-                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
-            }
+            Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
 
             // Statements we do not track.
             AscribeUserType(..) => {}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index cbfdb47dd1a..3fa40dc3059 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -678,7 +678,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             | StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index b7988625839..783ab350faa 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -7,9 +7,10 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
-    MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue,
-    SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
+    Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
+    ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+    TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::Subst;
@@ -636,11 +637,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     );
                 }
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+                let ty = op.ty(&self.body.local_decls, self.tcx);
+                if !ty.is_bool() {
+                    self.fail(
+                        location,
+                        format!("`assume` argument must be `bool`, but got: `{}`", ty),
+                    );
+                }
+            }
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+                CopyNonOverlapping { src, dst, count },
+            )) => {
                 let src_ty = src.ty(&self.body.local_decls, self.tcx);
                 let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
                     src_deref.ty
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index c5a450b0e2e..80ef166d57f 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1362,13 +1362,7 @@ impl Debug for Statement<'_> {
                 write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
             }
             Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
-            CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
-                write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
-            }
+            Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
             Nop => write!(fmt, "nop"),
         }
     }
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 6e64a3b80c1..4e06d91012c 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -249,7 +249,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         Retag(..) => "Retag",
         AscribeUserType(..) => "AscribeUserType",
         Coverage(..) => "Coverage",
-        CopyNonOverlapping(..) => "CopyNonOverlapping",
+        Intrinsic(..) => "Intrinsic",
         Nop => "Nop",
     }
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index d7b9d59eced..bf63b8efaf7 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -327,6 +327,34 @@ pub enum StatementKind<'tcx> {
     /// executed.
     Coverage(Box<Coverage>),
 
+    /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
+    /// This avoids adding a new block and a terminator for simple intrinsics.
+    Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
+
+    /// No-op. Useful for deleting instructions without affecting statement indices.
+    Nop,
+}
+
+#[derive(
+    Clone,
+    TyEncodable,
+    TyDecodable,
+    Debug,
+    PartialEq,
+    Hash,
+    HashStable,
+    TypeFoldable,
+    TypeVisitable
+)]
+pub enum NonDivergingIntrinsic<'tcx> {
+    /// Denotes a call to the intrinsic function `assume`.
+    ///
+    /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its
+    /// computation to infer information about other variables. So if the boolean came from a
+    /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks.
+    /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`.
+    Assume(Operand<'tcx>),
+
     /// Denotes a call to the intrinsic function `copy_nonoverlapping`.
     ///
     /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
@@ -340,10 +368,18 @@ pub enum StatementKind<'tcx> {
     ///
     /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
     /// I vaguely remember Ralf saying somewhere that he thought it should not be.
-    CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
+    CopyNonOverlapping(CopyNonOverlapping<'tcx>),
+}
 
-    /// No-op. Useful for deleting instructions without affecting statement indices.
-    Nop,
+impl std::fmt::Display for NonDivergingIntrinsic<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Assume(op) => write!(f, "assume({op:?})"),
+            Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
+            }
+        }
+    }
 }
 
 /// Describes what kind of retag is to be performed.
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 7bd65f42e3f..708ea4398c8 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -425,14 +425,15 @@ macro_rules! make_mir_visitor {
                             location
                         )
                     }
-                    StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
-                        src,
-                        dst,
-                        count,
-                    }) => {
-                      self.visit_operand(src, location);
-                      self.visit_operand(dst, location);
-                      self.visit_operand(count, location)
+                    StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => {
+                        match intrinsic {
+                            NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
+                            NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                                self.visit_operand(src, location);
+                                self.visit_operand(dst, location);
+                                self.visit_operand(count, location);
+                            }
+                        }
                     }
                     StatementKind::Nop => {}
                 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 483c1e274aa..3e08a8799ef 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -270,7 +270,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
             | StatementKind::Retag(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index f6b5af90a85..18760b6c6fa 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -142,7 +142,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
             | StatementKind::FakeRead(..)
             | StatementKind::Nop
             | StatementKind::Retag(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::StorageLive(..) => {}
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index c3258386223..f46fd118bde 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -330,7 +330,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 0f5fd77f7ab..beff19a3ab2 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -105,7 +105,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                 // safe (at least as emitted during MIR construction)
             }
 
-            StatementKind::CopyNonOverlapping(..) => unreachable!(),
+            // Move to above list once mir construction uses it.
+            StatementKind::Intrinsic(..) => unreachable!(),
         }
         self.super_statement(statement, location);
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 423e78317aa..9f842c929dc 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -825,7 +825,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
 
         // Retain spans from all other statements
         StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
-        | StatementKind::CopyNonOverlapping(..)
+        | StatementKind::Intrinsic(..)
         | StatementKind::Assign(_)
         | StatementKind::SetDiscriminant { .. }
         | StatementKind::Deinit(..)
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 9163672f570..3f3870cc7ba 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -52,7 +52,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
                 | StatementKind::StorageLive(_)
                 | StatementKind::StorageDead(_)
                 | StatementKind::Coverage(_)
-                | StatementKind::CopyNonOverlapping(_)
+                | StatementKind::Intrinsic(_)
                 | StatementKind::Nop => (),
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index da55510920e..9bc47613e4c 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -537,7 +537,7 @@ impl<'a> Conflicts<'a> {
             | StatementKind::FakeRead(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index dbff4a6bd69..705cf776fb2 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1452,7 +1452,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
             | StatementKind::Retag(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index b7ba616510c..9892580e63d 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -46,12 +46,31 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                         let mut args = args.drain(..);
                         block.statements.push(Statement {
                             source_info: terminator.source_info,
-                            kind: StatementKind::CopyNonOverlapping(Box::new(
-                                rustc_middle::mir::CopyNonOverlapping {
-                                    src: args.next().unwrap(),
-                                    dst: args.next().unwrap(),
-                                    count: args.next().unwrap(),
-                                },
+                            kind: StatementKind::Intrinsic(Box::new(
+                                NonDivergingIntrinsic::CopyNonOverlapping(
+                                    rustc_middle::mir::CopyNonOverlapping {
+                                        src: args.next().unwrap(),
+                                        dst: args.next().unwrap(),
+                                        count: args.next().unwrap(),
+                                    },
+                                ),
+                            )),
+                        });
+                        assert_eq!(
+                            args.next(),
+                            None,
+                            "Extra argument for copy_non_overlapping intrinsic"
+                        );
+                        drop(args);
+                        terminator.kind = TerminatorKind::Goto { target };
+                    }
+                    sym::assume => {
+                        let target = target.unwrap();
+                        let mut args = args.drain(..);
+                        block.statements.push(Statement {
+                            source_info: terminator.source_info,
+                            kind: StatementKind::Intrinsic(Box::new(
+                                NonDivergingIntrinsic::Assume(args.next().unwrap()),
                             )),
                         });
                         assert_eq!(
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 41a0bfac41a..f1bbf2ea7e8 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -51,7 +51,7 @@ impl RemoveNoopLandingPads {
                 StatementKind::Assign { .. }
                 | StatementKind::SetDiscriminant { .. }
                 | StatementKind::Deinit(..)
-                | StatementKind::CopyNonOverlapping(..)
+                | StatementKind::Intrinsic(..)
                 | StatementKind::Retag { .. } => {
                     return false;
                 }
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 190f9c1ac15..2f116aaa958 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -249,7 +249,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
             | StatementKind::StorageDead(_)
-            | StatementKind::CopyNonOverlapping(_)
+            | StatementKind::Intrinsic(_)
             | StatementKind::Nop => {}
         }
     }
@@ -317,7 +317,7 @@ fn find_determining_place<'tcx>(
             | StatementKind::Retag(_, _)
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
-            | StatementKind::CopyNonOverlapping(_)
+            | StatementKind::Intrinsic(_)
             | StatementKind::Nop => {}
 
             // If the discriminant is set, it is always set
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index bed48db959a..57d372fda56 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -499,7 +499,7 @@ impl UsedLocals {
 impl<'tcx> Visitor<'tcx> for UsedLocals {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match statement.kind {
-            StatementKind::CopyNonOverlapping(..)
+            StatementKind::Intrinsic(..)
             | StatementKind::Retag(..)
             | StatementKind::Coverage(..)
             | StatementKind::FakeRead(..)
diff --git a/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
new file mode 100644
index 00000000000..d9898d8e0f0
--- /dev/null
+++ b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
@@ -0,0 +1,26 @@
+- // MIR for `assume` before LowerIntrinsics
++ // MIR for `assume` after LowerIntrinsics
+  
+  fn assume() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
+      let _1: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-         _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
++         assume(const true);              // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:38: +2:39
+          _0 = const ();                   // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +3:6
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
new file mode 100644
index 00000000000..4fb6752b619
--- /dev/null
+++ b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
@@ -0,0 +1,72 @@
+- // MIR for `f_copy_nonoverlapping` before LowerIntrinsics
++ // MIR for `f_copy_nonoverlapping` after LowerIntrinsics
+  
+  fn f_copy_nonoverlapping() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:32
+      let _1: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+      let _3: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+      let mut _4: *const i32;              // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+      let mut _5: *const ();               // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+      let mut _6: *const ();               // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+      let _7: &();                         // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+      let mut _8: *mut i32;                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+      let mut _9: *mut ();                 // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+      let mut _10: *mut ();                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+      let mut _11: &mut ();                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+      scope 1 {
+          debug src => _1;                 // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+          let mut _2: ();                  // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+          scope 2 {
+              debug dst => _2;             // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+              scope 3 {
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+          Deinit(_1);                      // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+          Deinit(_2);                      // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21
+          StorageLive(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+          StorageLive(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+          StorageLive(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          StorageLive(_6);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          StorageLive(_7);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _7 = &_1;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _6 = &raw const (*_7);           // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _5 = _6;                         // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          _4 = move _5 as *const i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+          StorageDead(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:58: +4:59
+          StorageLive(_8);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+          StorageLive(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          StorageLive(_10);                // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          StorageLive(_11);                // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _11 = &mut _2;                   // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _10 = &raw mut (*_11);           // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _9 = _10;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          _8 = move _9 as *mut i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+          StorageDead(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
+-         _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:65:9: 65:28
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
++         copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
++         goto -> bb1;                     // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+      }
+  
+      bb1: {
+          StorageDead(_8);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+          StorageDead(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+          StorageDead(_11);                // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_10);                // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_7);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_6);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          _0 = const ();                   // scope 3 at $DIR/lower_intrinsics.rs:+3:5: +5:6
+          StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+          StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs
index 195543d42bb..66dae0e46b9 100644
--- a/src/test/mir-opt/lower_intrinsics.rs
+++ b/src/test/mir-opt/lower_intrinsics.rs
@@ -1,7 +1,7 @@
 // unit-test: LowerIntrinsics
 // ignore-wasm32 compiled with panic=abort by default
 
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, intrinsics)]
 #![crate_type = "lib"]
 
 // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -51,3 +51,24 @@ pub fn discriminant<T>(t: T) {
     core::intrinsics::discriminant_value(&());
     core::intrinsics::discriminant_value(&E::B);
 }
+
+extern "rust-intrinsic" {
+    // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
+    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+}
+
+// EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
+pub fn f_copy_nonoverlapping() {
+    let src = ();
+    let mut dst = ();
+    unsafe {
+        copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+    }
+}
+
+// EMIT_MIR lower_intrinsics.assume.LowerIntrinsics.diff
+pub fn assume() {
+    unsafe {
+        std::intrinsics::assume(true);
+    }
+}
diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
deleted file mode 100644
index 28536dc28a7..00000000000
--- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
+++ /dev/null
@@ -1,146 +0,0 @@
-- // MIR for `identity` before ConstProp
-+ // MIR for `identity` after ConstProp
-  
-  fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
-      let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
-      let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-      let mut _5: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let mut _7: !;                       // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      scope 1 {
-          debug residual => _6;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          scope 2 {
-              scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-                  debug residual => _8;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let _16: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _17: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  scope 9 {
-                      debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                      }
-                  }
-              }
-          }
-      }
-      scope 3 {
-          debug val => _9;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          scope 4 {
-          }
-      }
-      scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-          debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _10: isize;              // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _12: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let _13: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _14: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _15: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          scope 6 {
-              debug v => _11;              // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          }
-          scope 7 {
-              debug e => _13;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-          _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-          _10 = discriminant(_4);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-      }
-  
-      bb1: {
-          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  
-      bb3: {
-          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageLive(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          _8 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageLive(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
-  
-      bb4: {
-          StorageLive(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         _5 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  
-      bb5: {
-          unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-      }
-  
-      bb6: {
-          StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         _5 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  }
-  
diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
deleted file mode 100644
index df20f0ed36b..00000000000
--- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
+++ /dev/null
@@ -1,124 +0,0 @@
-// MIR for `identity` after PreCodegen
-
-fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
-    let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
-    let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-    let _5: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-    let mut _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    scope 1 {
-        debug residual => _5;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        scope 2 {
-            scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-                debug residual => _6;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let _14: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _15: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _16: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                scope 9 {
-                    debug e => _14;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                    scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                        debug t => _16;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                    }
-                }
-            }
-        }
-    }
-    scope 3 {
-        debug val => _7;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        scope 4 {
-        }
-    }
-    scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-        debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _8: isize;               // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let _9: i32;                     // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _10: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _12: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _13: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        scope 6 {
-            debug v => _9;               // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        }
-        scope 7 {
-            debug e => _11;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        }
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-        _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-        _8 = discriminant(_4);           // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb1: {
-        StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        _13 = move _11;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_12);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_12) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        _5 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        _6 = _5;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        _16 = move _14;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        _15 = move _16;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-        StorageDead(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageDead(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-    }
-
-    bb2: {
-        unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb3: {
-        StorageLive(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        _9 = move ((_4 as Ok).0: i32);   // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        _10 = move _9;                   // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        _7 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        _2 = _7;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-    }
-}
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
deleted file mode 100644
index 28269165e1c..00000000000
--- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
+++ /dev/null
@@ -1,103 +0,0 @@
-- // MIR for `too_complex` before ConstProp
-+ // MIR for `too_complex` after ConstProp
-  
-  fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
-      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
-      let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
-      let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-      let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
-      let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-      let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
-      let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-      let mut _7: usize;                   // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43
-      let mut _8: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33
-      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-      let mut _10: i32;                    // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
-      let _11: usize;                      // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-      scope 1 {
-          debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
-      }
-      scope 2 {
-          debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
-      }
-      scope 3 {
-          debug v => _9;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
-      }
-      scope 4 {
-          debug r => _11;                  // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-          _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
-      }
-  
-      bb1: {
-          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-          _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-          StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
--         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         _8 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-          _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-          StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
--         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         _8 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-      }
-  
-      bb4: {
-          StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-      }
-  
-      bb5: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-      }
-  
-      bb6: {
-          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-          _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-          StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
-          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-      }
-  
-      bb7: {
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
deleted file mode 100644
index 0ee070619e7..00000000000
--- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
+++ /dev/null
@@ -1,73 +0,0 @@
-// MIR for `too_complex` after PreCodegen
-
-fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
-    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
-    let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
-    let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-    let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
-    let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-    let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
-    let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-    let mut _8: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
-    let _9: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-    scope 1 {
-        debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
-    }
-    scope 2 {
-        debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
-    }
-    scope 3 {
-        debug v => _7;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
-    }
-    scope 4 {
-        debug r => _9;                   // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-        _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-        switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
-    }
-
-    bb1: {
-        StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-        StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
-        StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-        Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-        discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-        StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-    }
-
-    bb2: {
-        unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-    }
-
-    bb3: {
-        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-        _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-        StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-        _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-        Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
-        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-        _7 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-        StorageLive(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-        _8 = _7;                         // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-        Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        StorageDead(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
-        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-    }
-
-    bb4: {
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
-    }
-}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 74c222bbcbe..b22a9c81746 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -7,7 +7,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    TerminatorKind, NonDivergingIntrinsic
 };
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
@@ -212,11 +212,18 @@ fn check_statement<'tcx>(
             check_place(tcx, **place, span, body)
         },
 
-        StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+            check_operand(tcx, op, span, body)
+        },
+
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+            rustc_middle::mir::CopyNonOverlapping { dst, src, count },
+        )) => {
             check_operand(tcx, dst, span, body)?;
             check_operand(tcx, src, span, body)?;
             check_operand(tcx, count, span, body)
         },
+
         // These are all NOPs
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)