Auto merge of #106364 - JakobDegen:top-down-inlining, r=cjgillot

Reenable limited top-down MIR inlining

Reverts most of #105119 and uses an alternative strategy to prevent exponential blowup. Specifically, we allow doing top-down inlining up to depth at most five, and for at most one call site per nested body.

r? `@cjgillot`
This commit is contained in:
bors 2023-01-02 22:52:58 +00:00
commit 67d16171d7
11 changed files with 222 additions and 99 deletions

View File

@ -1,6 +1,7 @@
//! Inlining pass for MIR functions
use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@ -27,6 +28,8 @@
const UNKNOWN_SIZE_COST: usize = 10;
const TOP_DOWN_DEPTH_LIMIT: usize = 5;
pub struct Inline;
#[derive(Copy, Clone, Debug)]
@ -86,8 +89,13 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
let param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut this =
Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
let mut this = Inliner {
tcx,
param_env,
codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
history: Vec::new(),
changed: false,
};
let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
this.process_blocks(body, blocks);
this.changed
@ -98,12 +106,26 @@ struct Inliner<'tcx> {
param_env: ParamEnv<'tcx>,
/// Caller codegen attributes.
codegen_fn_attrs: &'tcx CodegenFnAttrs,
/// Stack of inlined instances.
/// We only check the `DefId` and not the substs because we want to
/// avoid inlining cases of polymorphic recursion.
/// The number of `DefId`s is finite, so checking history is enough
/// to ensure that we do not loop endlessly while inlining.
history: Vec<DefId>,
/// Indicates that the caller body has been modified.
changed: bool,
}
impl<'tcx> Inliner<'tcx> {
fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
// How many callsites in this body are we allowed to inline? We need to limit this in order
// to prevent super-linear growth in MIR size
let inline_limit = match self.history.len() {
0 => usize::MAX,
1..=TOP_DOWN_DEPTH_LIMIT => 1,
_ => return,
};
let mut inlined_count = 0;
for bb in blocks {
let bb_data = &caller_body[bb];
if bb_data.is_cleanup {
@ -122,12 +144,16 @@ fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBl
debug!("not-inlined {} [{}]", callsite.callee, reason);
continue;
}
Ok(_) => {
Ok(new_blocks) => {
debug!("inlined {}", callsite.callee);
self.changed = true;
// We could process the blocks returned by `try_inlining` here. However, that
// leads to exponential compile times due to the top-down nature of this kind
// of inlining.
inlined_count += 1;
if inlined_count == inline_limit {
return;
}
self.history.push(callsite.callee.def_id());
self.process_blocks(caller_body, new_blocks);
self.history.pop();
}
}
}
@ -301,6 +327,10 @@ fn resolve_callsite(
return None;
}
if self.history.contains(&callee.def_id()) {
return None;
}
let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
let source_info = SourceInfo { span: fn_span, ..terminator.source_info };

View File

@ -10,6 +10,8 @@
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {main}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
+ }
+ }
bb0: {
@ -27,10 +29,7 @@
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
+ _3 = <fn() {main} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
+ // mir::Constant
+ // + span: $DIR/cycle.rs:6:5: 6:6
+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {main}, ()) -> <fn() {main} as FnOnce<()>>::Output {<fn() {main} as Fn<()>>::call}, val: Value(<ZST>) }
+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
@ -40,19 +39,19 @@
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
+ bb2: {
+ bb2 (cleanup): {
+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
+ }
+
+ bb4: {
+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
+ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb4 (cleanup): {
+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
}
}

View File

@ -10,6 +10,8 @@
+ let _3: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ let mut _4: &fn() {g}; // in scope 1 at $DIR/cycle.rs:6:5: 6:6
+ let mut _5: (); // in scope 1 at $DIR/cycle.rs:6:5: 6:8
+ scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
+ }
+ }
bb0: {
@ -27,10 +29,7 @@
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ StorageLive(_5); // scope 1 at $DIR/cycle.rs:6:5: 6:8
+ _3 = <fn() {g} as Fn<()>>::call(move _4, move _5) -> [return: bb2, unwind: bb3]; // scope 1 at $DIR/cycle.rs:6:5: 6:8
+ // mir::Constant
+ // + span: $DIR/cycle.rs:6:5: 6:6
+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {g}, ()) -> <fn() {g} as FnOnce<()>>::Output {<fn() {g} as Fn<()>>::call}, val: Value(<ZST>) }
+ _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {
@ -40,19 +39,19 @@
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2
+ }
+
+ bb2: {
+ bb2 (cleanup): {
+ drop(_2) -> bb3; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
+ }
+
+ bb4: {
+ StorageDead(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
+ StorageDead(_4); // scope 1 at $DIR/cycle.rs:6:7: 6:8
+ StorageDead(_3); // scope 1 at $DIR/cycle.rs:6:8: 6:9
+ drop(_2) -> bb1; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb3 (cleanup): {
+ drop(_2) -> bb4; // scope 1 at $DIR/cycle.rs:7:1: 7:2
+ }
+
+ bb4 (cleanup): {
+ resume; // scope 1 at $DIR/cycle.rs:5:1: 7:2
}
}

View File

@ -8,43 +8,68 @@
+ let _2: (); // in scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+ let _3: (); // in scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ let _4: (); // in scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
+ scope 2 (inlined <() as F>::call) { // at $DIR/exponential_runtime.rs:73:9: 73:25
+ let _5: (); // in scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
+ let _6: (); // in scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
+ let _7: (); // in scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
- _1 = <() as G>::call() -> bb1; // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22
+ StorageLive(_2); // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+ _2 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:73:9: 73:25
+ StorageLive(_5); // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
+ _5 = <() as E>::call() -> bb3; // scope 2 at $DIR/exponential_runtime.rs:61:9: 61:25
// mir::Constant
- // + span: $DIR/exponential_runtime.rs:86:5: 86:20
- // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
+ // + span: $DIR/exponential_runtime.rs:73:9: 73:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+ // + span: $DIR/exponential_runtime.rs:61:9: 61:23
+ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
}
bb1: {
+ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
+ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ _3 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_3); // scope 1 at $DIR/exponential_runtime.rs:74:25: 74:26
+ StorageLive(_4); // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
+ _4 = <() as F>::call() -> bb3; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
+ _4 = <() as F>::call() -> bb2; // scope 1 at $DIR/exponential_runtime.rs:75:9: 75:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:75:9: 75:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
+ }
+
+ bb3: {
+ bb2: {
+ StorageDead(_4); // scope 1 at $DIR/exponential_runtime.rs:75:25: 75:26
StorageDead(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:22: +1:23
_0 = const (); // scope 0 at $DIR/exponential_runtime.rs:+0:11: +2:2
return; // scope 0 at $DIR/exponential_runtime.rs:+2:2: +2:2
+ }
+
+ bb3: {
+ StorageDead(_5); // scope 2 at $DIR/exponential_runtime.rs:61:25: 61:26
+ StorageLive(_6); // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
+ _6 = <() as E>::call() -> bb4; // scope 2 at $DIR/exponential_runtime.rs:62:9: 62:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:62:9: 62:23
+ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
+ }
+
+ bb4: {
+ StorageDead(_6); // scope 2 at $DIR/exponential_runtime.rs:62:25: 62:26
+ StorageLive(_7); // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
+ _7 = <() as E>::call() -> bb5; // scope 2 at $DIR/exponential_runtime.rs:63:9: 63:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:63:9: 63:23
+ // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
+ }
+
+ bb5: {
+ StorageDead(_7); // scope 2 at $DIR/exponential_runtime.rs:63:25: 63:26
+ StorageDead(_2); // scope 1 at $DIR/exponential_runtime.rs:73:25: 73:26
+ StorageLive(_3); // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ _3 = <() as F>::call() -> bb1; // scope 1 at $DIR/exponential_runtime.rs:74:9: 74:25
+ // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:74:9: 74:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) }
}
}

View File

@ -5,17 +5,20 @@
let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
+ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
+ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
+ }
+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
+ _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline_cycle.rs:43:9: 43:23
+ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
// mir::Constant
- // + span: $DIR/inline_cycle.rs:14:5: 14:22
- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+ // + span: $DIR/inline_cycle.rs:43:9: 43:21
+ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
+ // + span: $DIR/inline_cycle.rs:36:9: 36:26
// + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {

View File

@ -9,6 +9,8 @@
+ debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
+ let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ let mut _4: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
+ }
+ }
bb0: {
@ -24,10 +26,7 @@
// + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ _3 = <fn() {f} as FnOnce<()>>::call_once(move _2, move _4) -> bb1; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
+ // mir::Constant
+ // + span: $DIR/inline_cycle.rs:54:5: 54:6
+ // + literal: Const { ty: extern "rust-call" fn(fn() {f}, ()) -> <fn() {f} as FnOnce<()>>::Output {<fn() {f} as FnOnce<()>>::call_once}, val: Value(<ZST>) }
+ _3 = move _2() -> bb1; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb1: {

View File

@ -6,18 +6,21 @@
let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
+ scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
+ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
+ }
+ }
+ }
+ }
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
+ _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline_cycle_generic.rs:31:9: 31:28
+ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
// mir::Constant
- // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
- // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+ // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
+ // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(<ZST>) }
// + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {

View File

@ -20,6 +20,8 @@
+ debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
+ }
+ }
+ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
+ }
+ }
bb0: {
@ -38,25 +40,10 @@
+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
+ StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
+ _3 = <fn() -> ! {sleep} as Fn<()>>::call(move _4, move _5) -> [return: bb1, unwind: bb5]; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
+ // mir::Constant
+ // + span: $DIR/inline_diverging.rs:27:13: 27:14
+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
+ _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ }
+
+ bb1: {
+ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
+ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
+ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
+ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
+ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
+ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb2, unwind: bb4]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
+ // mir::Constant
+ // + span: $DIR/inline_diverging.rs:28:13: 28:14
+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_7); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
+ StorageDead(_6); // scope 2 at $DIR/inline_diverging.rs:28:15: 28:16
+ StorageLive(_8); // scope 3 at $DIR/inline_diverging.rs:29:6: 29:7
@ -66,23 +53,35 @@
+ (_1.1: !) = move _9; // scope 3 at $DIR/inline_diverging.rs:29:5: 29:11
+ StorageDead(_8); // scope 3 at $DIR/inline_diverging.rs:29:10: 29:11
+ StorageDead(_3); // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ drop(_2) -> bb3; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ drop(_2) -> bb2; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
+ bb3: {
+ bb2: {
+ unreachable; // scope 0 at $DIR/inline_diverging.rs:30:2: 30:2
+ }
+
+ bb3 (cleanup): {
+ drop(_3) -> bb4; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
+ bb4 (cleanup): {
+ drop(_3) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ drop(_2) -> bb5; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ }
+
+ bb5 (cleanup): {
+ drop(_2) -> bb6; // scope 1 at $DIR/inline_diverging.rs:30:1: 30:2
+ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
+ }
+
+ bb6 (cleanup): {
+ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2
+ bb6: {
+ StorageDead(_5); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
+ StorageDead(_4); // scope 1 at $DIR/inline_diverging.rs:27:15: 27:16
+ StorageLive(_6); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
+ _6 = &_2; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:14
+ StorageLive(_7); // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
+ _9 = <fn() -> ! {sleep} as Fn<()>>::call(move _6, move _7) -> [return: bb1, unwind: bb3]; // scope 2 at $DIR/inline_diverging.rs:28:13: 28:16
+ // mir::Constant
+ // + span: $DIR/inline_diverging.rs:28:13: 28:14
+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() -> ! {sleep}, ()) -> <fn() -> ! {sleep} as FnOnce<()>>::Output {<fn() -> ! {sleep} as Fn<()>>::call}, val: Value(<ZST>) }
}
}

View File

@ -22,6 +22,9 @@
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
}
}
}
}
@ -92,11 +95,18 @@
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 = <i32 as From<i32>>::from(move _18) -> bb8; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+ _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/result.rs:LL:COL
// + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) }
_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
}
- bb5: {
@ -142,20 +152,5 @@
+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
+ switchInt(move _5) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
}
- bb8: {
+ bb7: {
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
}
}

View File

@ -0,0 +1,52 @@
// MIR for `ezmap` after PreCodegen
fn ezmap(_1: Option<i32>) -> Option<i32> {
debug x => _1; // in scope 0 at $DIR/simple_option_map_e2e.rs:+0:14: +0:15
let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/simple_option_map_e2e.rs:+0:33: +0:44
let mut _2: [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]; // in scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
scope 1 (inlined map::<i32, i32, [closure@$DIR/simple_option_map_e2e.rs:14:12: 14:15]>) { // at $DIR/simple_option_map_e2e.rs:14:5: 14:22
debug slf => _1; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:17: 2:20
debug f => _2; // in scope 1 at $DIR/simple_option_map_e2e.rs:2:33: 2:34
let mut _3: isize; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:9: 7:16
let mut _4: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
let mut _5: i32; // in scope 1 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
scope 2 {
debug x => _5; // in scope 2 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
scope 3 (inlined ezmap::{closure#0}) { // at $DIR/simple_option_map_e2e.rs:7:25: 7:29
debug n => _5; // in scope 3 at $DIR/simple_option_map_e2e.rs:+1:13: +1:14
}
}
}
bb0: {
StorageLive(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:12: +1:21
_3 = discriminant(_1); // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
switchInt(move _3) -> [0: bb1, 1: bb3, otherwise: bb2]; // scope 1 at $DIR/simple_option_map_e2e.rs:6:5: 6:14
}
bb1: {
Deinit(_0); // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
discriminant(_0) = 0; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:8:17: 8:21
}
bb2: {
unreachable; // scope 1 at $DIR/simple_option_map_e2e.rs:6:11: 6:14
}
bb3: {
_5 = move ((_1 as Some).0: i32); // scope 1 at $DIR/simple_option_map_e2e.rs:7:14: 7:15
StorageLive(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:25: 7:29
_4 = Add(move _5, const 1_i32); // scope 3 at $DIR/simple_option_map_e2e.rs:+1:16: +1:21
Deinit(_0); // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
((_0 as Some).0: i32) = move _4; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
discriminant(_0) = 1; // scope 2 at $DIR/simple_option_map_e2e.rs:7:20: 7:30
StorageDead(_4); // scope 2 at $DIR/simple_option_map_e2e.rs:7:29: 7:30
goto -> bb4; // scope 1 at $DIR/simple_option_map_e2e.rs:10:1: 10:2
}
bb4: {
StorageDead(_2); // scope 0 at $DIR/simple_option_map_e2e.rs:+1:21: +1:22
return; // scope 0 at $DIR/simple_option_map_e2e.rs:+2:2: +2:2
}
}

View File

@ -0,0 +1,19 @@
#[inline(always)]
fn map<T, U, F>(slf: Option<T>, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
{
match slf {
Some(x) => Some(f(x)),
None => None,
}
}
// EMIT_MIR simple_option_map_e2e.ezmap.PreCodegen.after.mir
pub fn ezmap(x: Option<i32>) -> Option<i32> {
map(x, |n| n + 1)
}
fn main() {
assert_eq!(None, ezmap(None));
}