Skip to content

Commit 3f07645

Browse files
committed
Lower the assume intrinsic to a MIR statement
1 parent 3c72788 commit 3f07645

File tree

33 files changed

+212
-30
lines changed

33 files changed

+212
-30
lines changed

compiler/rustc_borrowck/src/dataflow.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
392392
| mir::StatementKind::AscribeUserType(..)
393393
| mir::StatementKind::Coverage(..)
394394
| mir::StatementKind::CopyNonOverlapping(..)
395+
| mir::StatementKind::Assume(..)
395396
| mir::StatementKind::Nop => {}
396397
}
397398
}

compiler/rustc_borrowck/src/invalidation.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
7272
self.consume_operand(location, dst);
7373
self.consume_operand(location, count);
7474
}
75-
StatementKind::Nop
75+
// Only relevant for mir typeck
76+
StatementKind::AscribeUserType(..)
77+
// Doesn't have any language semantics
7678
| StatementKind::Coverage(..)
77-
| StatementKind::AscribeUserType(..)
78-
| StatementKind::Retag { .. }
79-
| StatementKind::StorageLive(..) => {
80-
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
81-
// to borrow check.
82-
}
79+
// Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck
80+
| StatementKind::Assume(..)
81+
// Does not actually affect borrowck
82+
| StatementKind::StorageLive(..) => {}
8383
StatementKind::StorageDead(local) => {
8484
self.access_place(
8585
location,
@@ -88,7 +88,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
8888
LocalMutationIsAllowed::Yes,
8989
);
9090
}
91-
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
91+
StatementKind::Nop
92+
| StatementKind::Retag { .. }
93+
| StatementKind::Deinit(..)
94+
| StatementKind::SetDiscriminant { .. } => {
9295
bug!("Statement not allowed in this MIR phase")
9396
}
9497
}

compiler/rustc_borrowck/src/lib.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -599,14 +599,14 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
599599
"Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
600600
)
601601
}
602-
StatementKind::Nop
602+
// Only relevant for mir typeck
603+
StatementKind::AscribeUserType(..)
604+
// Doesn't have any language semantics
603605
| StatementKind::Coverage(..)
604-
| StatementKind::AscribeUserType(..)
605-
| StatementKind::Retag { .. }
606-
| StatementKind::StorageLive(..) => {
607-
// `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
608-
// to borrow check.
609-
}
606+
// Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck
607+
| StatementKind::Assume(..)
608+
// Does not actually affect borrowck
609+
| StatementKind::StorageLive(..) => {}
610610
StatementKind::StorageDead(local) => {
611611
self.access_place(
612612
location,
@@ -616,7 +616,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
616616
flow_state,
617617
);
618618
}
619-
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
619+
StatementKind::Nop
620+
| StatementKind::Retag { .. }
621+
| StatementKind::Deinit(..)
622+
| StatementKind::SetDiscriminant { .. } => {
620623
bug!("Statement not allowed in this MIR phase")
621624
}
622625
}

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13091309
"Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
13101310
),
13111311
StatementKind::FakeRead(..)
1312+
| StatementKind::Assume(..)
13121313
| StatementKind::StorageLive(..)
13131314
| StatementKind::StorageDead(..)
13141315
| StatementKind::Retag { .. }

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,8 @@ fn codegen_stmt<'tcx>(
791791
| StatementKind::Nop
792792
| StatementKind::FakeRead(..)
793793
| StatementKind::Retag { .. }
794+
// We ignore `assume` intrinsics, they are only useful for optimizations
795+
| StatementKind::Assume(..)
794796
| StatementKind::AscribeUserType(..) => {}
795797

796798
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
540540
return None;
541541
} // conservative handling
542542
StatementKind::Assign(_)
543+
| StatementKind::Assume(_)
543544
| StatementKind::FakeRead(_)
544545
| StatementKind::SetDiscriminant { .. }
545546
| StatementKind::Deinit(_)

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
357357
let usize_layout = fx.layout_of(fx.tcx.types.usize);
358358

359359
match intrinsic {
360-
sym::assume => {
361-
intrinsic_args!(fx, args => (_a); intrinsic);
362-
}
363360
sym::likely | sym::unlikely => {
364361
intrinsic_args!(fx, args => (a); intrinsic);
365362

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
7777
let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
7878

7979
let llval = match name {
80-
sym::assume => {
81-
bx.assume(args[0].immediate());
82-
return;
83-
}
8480
sym::abort => {
8581
bx.abort();
8682
return;

compiler/rustc_codegen_ssa/src/mir/statement.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
9393
bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
9494
bx
9595
}
96+
mir::StatementKind::Assume(box ref op) => {
97+
let op_val = self.codegen_operand(&mut bx, op);
98+
bx.assume(op_val.immediate());
99+
bx
100+
}
96101
mir::StatementKind::FakeRead(..)
97102
| mir::StatementKind::Retag { .. }
98103
| mir::StatementKind::AscribeUserType(..)

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -506,12 +506,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
506506
// These just return their argument
507507
self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
508508
}
509-
sym::assume => {
510-
let cond = self.read_scalar(&args[0])?.to_bool()?;
511-
if !cond {
512-
throw_ub_format!("`assume` intrinsic called with `false`");
513-
}
514-
}
515509
sym::raw_eq => {
516510
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
517511
self.write_scalar(result, dest)?;

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
122122
self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
123123
}
124124

125+
// Call Assume
126+
Assume(box op) => {
127+
let op = self.eval_operand(op, None)?;
128+
let cond = self.read_scalar(&op)?.to_bool()?;
129+
if !cond {
130+
throw_ub_format!("`assume` called with `false`");
131+
}
132+
}
133+
125134
// Statements we do not track.
126135
AscribeUserType(..) => {}
127136

compiler/rustc_const_eval/src/transform/check_consts/check.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
679679
| StatementKind::AscribeUserType(..)
680680
| StatementKind::Coverage(..)
681681
| StatementKind::CopyNonOverlapping(..)
682+
| StatementKind::Assume(..)
682683
| StatementKind::Nop => {}
683684
}
684685
}

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
636636
);
637637
}
638638
}
639+
StatementKind::Assume(box ref op) => {
640+
let ty = op.ty(&self.body.local_decls, self.tcx);
641+
if !ty.is_bool() {
642+
self.fail(
643+
location,
644+
format!("`assume` argument must be `bool`, but got: `{}`", ty),
645+
);
646+
}
647+
}
639648
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
640649
ref src,
641650
ref dst,

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,7 @@ impl Debug for Statement<'_> {
13771377
}) => {
13781378
write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
13791379
}
1380+
Assume(box ref cond) => write!(fmt, "assume({:?})", cond),
13801381
Nop => write!(fmt, "nop"),
13811382
}
13821383
}

compiler/rustc_middle/src/mir/spanview.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
250250
AscribeUserType(..) => "AscribeUserType",
251251
Coverage(..) => "Coverage",
252252
CopyNonOverlapping(..) => "CopyNonOverlapping",
253+
Assume(..) => "Assume",
253254
Nop => "Nop",
254255
}
255256
}

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,14 @@ pub enum StatementKind<'tcx> {
342342
/// I vaguely remember Ralf saying somewhere that he thought it should not be.
343343
CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
344344

345+
/// Denotes a call to the intrinsic function `assume`.
346+
///
347+
/// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its
348+
/// computation to infer information about other variables. So if the boolean came from a
349+
/// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks.
350+
/// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`.
351+
Assume(Box<Operand<'tcx>>),
352+
345353
/// No-op. Useful for deleting instructions without affecting statement indices.
346354
Nop,
347355
}

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,9 @@ macro_rules! make_mir_visitor {
434434
self.visit_operand(dst, location);
435435
self.visit_operand(count, location)
436436
}
437+
StatementKind::Assume(box ref $($mutability)? val) => {
438+
self.visit_operand(val, location)
439+
}
437440
StatementKind::Nop => {}
438441
}
439442
}

compiler/rustc_mir_dataflow/src/impls/liveness.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
271271
| StatementKind::AscribeUserType(..)
272272
| StatementKind::Coverage(..)
273273
| StatementKind::CopyNonOverlapping(..)
274+
| StatementKind::Assume(..)
274275
| StatementKind::Nop => None,
275276
};
276277
if let Some(destination) = destination {

compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
143143
| StatementKind::Nop
144144
| StatementKind::Retag(..)
145145
| StatementKind::CopyNonOverlapping(..)
146+
| StatementKind::Assume(..)
146147
| StatementKind::StorageLive(..) => {}
147148
}
148149
}

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
331331
| StatementKind::AscribeUserType(..)
332332
| StatementKind::Coverage(..)
333333
| StatementKind::CopyNonOverlapping(..)
334+
| StatementKind::Assume(..)
334335
| StatementKind::Nop => {}
335336
}
336337
}

compiler/rustc_mir_transform/src/check_unsafety.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
105105
// safe (at least as emitted during MIR construction)
106106
}
107107

108+
// Move to above list once mir construction uses it.
109+
StatementKind::Assume(..) => unreachable!(),
110+
108111
StatementKind::CopyNonOverlapping(..) => unreachable!(),
109112
}
110113
self.super_statement(statement, location);

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
826826
// Retain spans from all other statements
827827
StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
828828
| StatementKind::CopyNonOverlapping(..)
829+
| StatementKind::Assume(..)
829830
| StatementKind::Assign(_)
830831
| StatementKind::SetDiscriminant { .. }
831832
| StatementKind::Deinit(..)

compiler/rustc_mir_transform/src/dead_store_elimination.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
5353
| StatementKind::StorageDead(_)
5454
| StatementKind::Coverage(_)
5555
| StatementKind::CopyNonOverlapping(_)
56+
| StatementKind::Assume(_)
5657
| StatementKind::Nop => (),
5758

5859
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {

compiler/rustc_mir_transform/src/dest_prop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ impl<'a> Conflicts<'a> {
538538
| StatementKind::AscribeUserType(..)
539539
| StatementKind::Coverage(..)
540540
| StatementKind::CopyNonOverlapping(..)
541+
| StatementKind::Assume(..)
541542
| StatementKind::Nop => {}
542543
}
543544
}

compiler/rustc_mir_transform/src/generator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
14531453
| StatementKind::AscribeUserType(..)
14541454
| StatementKind::Coverage(..)
14551455
| StatementKind::CopyNonOverlapping(..)
1456+
| StatementKind::Assume(..)
14561457
| StatementKind::Nop => {}
14571458
}
14581459
}

compiler/rustc_mir_transform/src/lower_intrinsics.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
6262
drop(args);
6363
terminator.kind = TerminatorKind::Goto { target };
6464
}
65+
sym::assume => {
66+
let target = target.unwrap();
67+
let mut args = args.drain(..);
68+
block.statements.push(Statement {
69+
source_info: terminator.source_info,
70+
kind: StatementKind::Assume(Box::new(args.next().unwrap())),
71+
});
72+
assert_eq!(args.next(), None, "Extra argument for assume intrinsic");
73+
drop(args);
74+
terminator.kind = TerminatorKind::Goto { target };
75+
}
6576
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
6677
if let Some(target) = *target {
6778
let lhs;

compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ impl RemoveNoopLandingPads {
5252
| StatementKind::SetDiscriminant { .. }
5353
| StatementKind::Deinit(..)
5454
| StatementKind::CopyNonOverlapping(..)
55+
| StatementKind::Assume(..)
5556
| StatementKind::Retag { .. } => {
5657
return false;
5758
}

compiler/rustc_mir_transform/src/separate_const_switch.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
250250
| StatementKind::Coverage(_)
251251
| StatementKind::StorageDead(_)
252252
| StatementKind::CopyNonOverlapping(_)
253+
| StatementKind::Assume(_)
253254
| StatementKind::Nop => {}
254255
}
255256
}
@@ -318,6 +319,7 @@ fn find_determining_place<'tcx>(
318319
| StatementKind::AscribeUserType(_, _)
319320
| StatementKind::Coverage(_)
320321
| StatementKind::CopyNonOverlapping(_)
322+
| StatementKind::Assume(_)
321323
| StatementKind::Nop => {}
322324

323325
// If the discriminant is set, it is always set

compiler/rustc_mir_transform/src/simplify.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
500500
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
501501
match statement.kind {
502502
StatementKind::CopyNonOverlapping(..)
503+
| StatementKind::Assume(..)
503504
| StatementKind::Retag(..)
504505
| StatementKind::Coverage(..)
505506
| StatementKind::FakeRead(..)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
- // MIR for `assume` before LowerIntrinsics
2+
+ // MIR for `assume` after LowerIntrinsics
3+
4+
fn assume() -> () {
5+
let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
6+
let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:38
7+
scope 1 {
8+
}
9+
10+
bb0: {
11+
StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
12+
- _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
13+
- // mir::Constant
14+
- // + span: $DIR/lower_intrinsics.rs:97:9: 97:32
15+
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
16+
+ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
17+
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
18+
}
19+
20+
bb1: {
21+
StorageDead(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:38: +2:39
22+
_0 = const (); // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +3:6
23+
return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
24+
}
25+
}
26+

0 commit comments

Comments
 (0)