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:
commit
67d16171d7
@ -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 };
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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: {
|
||||
|
@ -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: {
|
||||
|
@ -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: {
|
||||
|
@ -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>) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
19
src/test/mir-opt/simple_option_map_e2e.rs
Normal file
19
src/test/mir-opt/simple_option_map_e2e.rs
Normal 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));
|
||||
}
|
Loading…
Reference in New Issue
Block a user