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
This commit is contained in:
bors 2022-09-07 09:47:23 +00:00
commit e7c7aa7288
37 changed files with 338 additions and 570 deletions

View File

@ -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 => {}
}
}

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

@ -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(..)

View File

@ -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);
}
},
}
}

View File

@ -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 { .. }

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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>,

View File

@ -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(..) => {}

View File

@ -678,7 +678,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}

View File

@ -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

View File

@ -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"),
}
}

View File

@ -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",
}
}

View File

@ -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.

View File

@ -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 => {}
}

View File

@ -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 {

View File

@ -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(..) => {}
}
}

View File

@ -330,7 +330,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}

View File

@ -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);
}

View File

@ -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(..)

View File

@ -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(_, _) => {

View File

@ -537,7 +537,7 @@ impl<'a> Conflicts<'a> {
| StatementKind::FakeRead(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}

View File

@ -1452,7 +1452,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
| StatementKind::Retag(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Intrinsic(..)
| StatementKind::Nop => {}
}
}

View File

@ -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!(

View File

@ -51,7 +51,7 @@ impl RemoveNoopLandingPads {
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
| StatementKind::Deinit(..)
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Intrinsic(..)
| StatementKind::Retag { .. } => {
return false;
}

View File

@ -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

View File

@ -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(..)

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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(_)