Reenable limited top-down MIR inlining

This commit is contained in:
Jakob Degen 2023-01-01 22:01:29 -08:00
parent bb6e76df06
commit ee6503a706
11 changed files with 222 additions and 99 deletions

View file

@ -1,6 +1,7 @@
//! Inlining pass for MIR functions //! Inlining pass for MIR functions
use crate::deref_separator::deref_finder; use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr; use rustc_attr::InlineAttr;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@ -27,6 +28,8 @@ const RESUME_PENALTY: usize = 45;
const UNKNOWN_SIZE_COST: usize = 10; const UNKNOWN_SIZE_COST: usize = 10;
const TOP_DOWN_DEPTH_LIMIT: usize = 5;
pub struct Inline; pub struct Inline;
#[derive(Copy, Clone, Debug)] #[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 param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut this = let mut this = Inliner {
Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false }; 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(); let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
this.process_blocks(body, blocks); this.process_blocks(body, blocks);
this.changed this.changed
@ -98,12 +106,26 @@ struct Inliner<'tcx> {
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
/// Caller codegen attributes. /// Caller codegen attributes.
codegen_fn_attrs: &'tcx CodegenFnAttrs, 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. /// Indicates that the caller body has been modified.
changed: bool, changed: bool,
} }
impl<'tcx> Inliner<'tcx> { impl<'tcx> Inliner<'tcx> {
fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) { 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 { for bb in blocks {
let bb_data = &caller_body[bb]; let bb_data = &caller_body[bb];
if bb_data.is_cleanup { if bb_data.is_cleanup {
@ -122,12 +144,16 @@ impl<'tcx> Inliner<'tcx> {
debug!("not-inlined {} [{}]", callsite.callee, reason); debug!("not-inlined {} [{}]", callsite.callee, reason);
continue; continue;
} }
Ok(_) => { Ok(new_blocks) => {
debug!("inlined {}", callsite.callee); debug!("inlined {}", callsite.callee);
self.changed = true; self.changed = true;
// We could process the blocks returned by `try_inlining` here. However, that inlined_count += 1;
// leads to exponential compile times due to the top-down nature of this kind if inlined_count == inline_limit {
// of inlining. return;
}
self.history.push(callsite.callee.def_id());
self.process_blocks(caller_body, new_blocks);
self.history.pop();
} }
} }
} }
@ -301,6 +327,10 @@ impl<'tcx> Inliner<'tcx> {
return None; 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 fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
let source_info = SourceInfo { span: fn_span, ..terminator.source_info }; 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 _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 _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 + 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: { bb0: {
@ -27,10 +29,7 @@
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // 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 + 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 + _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ // 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>) }
} }
bb1: { bb1: {
@ -40,19 +39,19 @@
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 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(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
+ StorageDead(_4); // 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 + 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 + 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 _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 _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 + 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: { bb0: {
@ -27,10 +29,7 @@
+ StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6 + StorageLive(_4); // scope 1 at $DIR/cycle.rs:6:5: 6:6
+ _4 = &_2; // 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 + 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 + _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ // 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>) }
} }
bb1: { bb1: {
@ -40,19 +39,19 @@
return; // scope 0 at $DIR/cycle.rs:+2:2: +2:2 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(_5); // scope 1 at $DIR/cycle.rs:6:7: 6:8
+ StorageDead(_4); // 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 + 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 + 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 _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 _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 + 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: { bb0: {
StorageLive(_1); // scope 0 at $DIR/exponential_runtime.rs:+1:5: +1:22 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 - _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 + 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 // mir::Constant
- // + span: $DIR/exponential_runtime.rs:86:5: 86:20 - // + span: $DIR/exponential_runtime.rs:86:5: 86:20
- // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) } - // + literal: Const { ty: fn() {<() as G>::call}, val: Value(<ZST>) }
+ // + span: $DIR/exponential_runtime.rs:73:9: 73:23 + // + span: $DIR/exponential_runtime.rs:61:9: 61:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) } + // + literal: Const { ty: fn() {<() as E>::call}, val: Value(<ZST>) }
} }
bb1: { 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 + 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 + 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 + // mir::Constant
+ // + span: $DIR/exponential_runtime.rs:75:9: 75:23 + // + span: $DIR/exponential_runtime.rs:75:9: 75:23
+ // + literal: Const { ty: fn() {<() as F>::call}, val: Value(<ZST>) } + // + 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(_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 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 _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 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 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 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 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: { bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24 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 = <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 // mir::Constant
- // + span: $DIR/inline_cycle.rs:14:5: 14:22 - // + 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:36:9: 36:26
+ // + span: $DIR/inline_cycle.rs:43:9: 43:21 // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
+ // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(<ZST>) }
} }
bb1: { bb1: {

View file

@ -9,6 +9,8 @@
+ debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23 + 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 _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 + 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: { bb0: {
@ -24,10 +26,7 @@
// + literal: Const { ty: fn() {f}, val: Value(<ZST>) } // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
+ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8 + 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 + 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 + _3 = move _2() -> bb1; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ // 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>) }
} }
bb1: { bb1: {

View file

@ -6,18 +6,21 @@
let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24 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 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 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: { bb0: {
StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24 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 = <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 // mir::Constant
- // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22 - // + 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 + // + 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: { bb1: {

View file

@ -20,6 +20,8 @@
+ debug b => _9; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10 + 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: { bb0: {
@ -38,25 +40,10 @@
+ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14 + 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 + _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 + 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 + _3 = move (*_4)() -> [return: bb6, unwind: bb4]; // scope 4 at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ // 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>) }
+ } + }
+ +
+ bb1: { + 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(_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 + 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 + 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 + (_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(_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 + 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 + 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): { + 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): { + 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): { + bb6: {
+ resume; // scope 1 at $DIR/inline_diverging.rs:26:1: 30:2 + 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 let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
scope 9 { scope 9 {
debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL 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(_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 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 _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 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ _17 = <i32 as From<i32>>::from(move _18) -> bb7; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
// mir::Constant Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
// + span: $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
// + literal: Const { ty: fn(i32) -> i32 {<i32 as From<i32>>::from}, val: Value(<ZST>) } 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: { - bb5: {
@ -142,20 +152,5 @@
+ _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + _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 + 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));
}