diff options
author | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2022-06-30 08:16:05 +0000 |
---|---|---|
committer | Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de> | 2022-09-06 14:18:32 +0000 |
commit | 3f076451202409bca6262d7b5bf9a4fee3d18fb9 (patch) | |
tree | caa5cf3deff3fb465f57d9a2a01641048bd60d1a /compiler | |
parent | 3c7278846102bb829c9a789e91bc43f0ed612943 (diff) | |
download | rust-3f076451202409bca6262d7b5bf9a4fee3d18fb9.tar.gz |
Lower the assume intrinsic to a MIR statement
Diffstat (limited to 'compiler')
29 files changed, 89 insertions, 29 deletions
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 816288eb50b..ec5fa76ff8b 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -392,6 +392,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Coverage(..) | mir::StatementKind::CopyNonOverlapping(..) + | mir::StatementKind::Assume(..) | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index ec521b1cf0a..03ad973cf49 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -72,14 +72,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { 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. - } + // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck + | StatementKind::Assume(..) + // Does not actually affect borrowck + | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( location, @@ -88,7 +88,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..663c880d0ae 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -599,14 +599,14 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx "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. - } + // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck + | StatementKind::Assume(..) + // Does not actually affect borrowck + | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( location, @@ -616,7 +616,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..e7713bda82c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1309,6 +1309,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", ), StatementKind::FakeRead(..) + | StatementKind::Assume(..) | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Retag { .. } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index c412e451a03..1f49ead93a3 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -791,6 +791,8 @@ fn codegen_stmt<'tcx>( | StatementKind::Nop | StatementKind::FakeRead(..) | StatementKind::Retag { .. } + // We ignore `assume` intrinsics, they are only useful for optimizations + | StatementKind::Assume(..) | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"), diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 9224f499339..f75de9096f3 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -540,6 +540,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( return None; } // conservative handling StatementKind::Assign(_) + | StatementKind::Assume(_) | StatementKind::FakeRead(_) | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(_) 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..9869e61280d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -93,6 +93,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); bx } + mir::StatementKind::Assume(box ref op) => { + let op_val = self.codegen_operand(&mut bx, op); + bx.assume(op_val.immediate()); + bx + } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } | mir::StatementKind::AscribeUserType(..) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index adda9639990..8157ae2e5b8 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -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)?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6b827149f50..3ac1d1b3198 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -122,6 +122,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; } + // Call Assume + Assume(box 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`"); + } + } + // 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..347c31ceeeb 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -679,6 +679,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b7988625839..dea445f6066 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -636,6 +636,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + StatementKind::Assume(box ref 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::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { ref src, ref dst, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f3676604bb0..48eb292c490 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1377,6 +1377,7 @@ impl Debug for Statement<'_> { }) => { write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count) } + Assume(box ref cond) => write!(fmt, "assume({:?})", cond), Nop => write!(fmt, "nop"), } } diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 6e64a3b80c1..cb5adee6910 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -250,6 +250,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { AscribeUserType(..) => "AscribeUserType", Coverage(..) => "Coverage", CopyNonOverlapping(..) => "CopyNonOverlapping", + Assume(..) => "Assume", Nop => "Nop", } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index d7b9d59eced..01ac2456a13 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -342,6 +342,14 @@ pub enum StatementKind<'tcx> { /// I vaguely remember Ralf saying somewhere that he thought it should not be. CopyNonOverlapping(Box<CopyNonOverlapping<'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(Box<Operand<'tcx>>), + /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 7bd65f42e3f..a0273e78b8f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -434,6 +434,9 @@ macro_rules! make_mir_visitor { self.visit_operand(dst, location); self.visit_operand(count, location) } + StatementKind::Assume(box ref $($mutability)? val) => { + self.visit_operand(val, 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..f3ea84e6350 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -271,6 +271,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | 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..bab224a7e04 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -143,6 +143,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc | StatementKind::Nop | StatementKind::Retag(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | 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..d7ea3339a69 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -331,6 +331,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 0f5fd77f7ab..1a360a8d40b 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -105,6 +105,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // safe (at least as emitted during MIR construction) } + // Move to above list once mir construction uses it. + StatementKind::Assume(..) => unreachable!(), + StatementKind::CopyNonOverlapping(..) => 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..f5e91371b58 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -826,6 +826,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::Assume(..) | 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..e95c5d888b2 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -53,6 +53,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::StorageDead(_) | StatementKind::Coverage(_) | StatementKind::CopyNonOverlapping(_) + | StatementKind::Assume(_) | 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..a2e12e40be9 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -538,6 +538,7 @@ impl<'a> Conflicts<'a> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index dbff4a6bd69..2bfcd82de5e 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1453,6 +1453,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index b7ba616510c..652c344ee14 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -62,6 +62,17 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { 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::Assume(Box::new(args.next().unwrap())), + }); + assert_eq!(args.next(), None, "Extra argument for assume intrinsic"); + drop(args); + terminator.kind = TerminatorKind::Goto { target }; + } sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { if let Some(target) = *target { let lhs; 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..7d1ab06c3bd 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -52,6 +52,7 @@ impl RemoveNoopLandingPads { | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | 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..34df693cf68 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -250,6 +250,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | StatementKind::Coverage(_) | StatementKind::StorageDead(_) | StatementKind::CopyNonOverlapping(_) + | StatementKind::Assume(_) | StatementKind::Nop => {} } } @@ -318,6 +319,7 @@ fn find_determining_place<'tcx>( | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) | StatementKind::CopyNonOverlapping(_) + | StatementKind::Assume(_) | 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..b51d6d6f4fe 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -500,6 +500,7 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match statement.kind { StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Retag(..) | StatementKind::Coverage(..) | StatementKind::FakeRead(..) |