-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Try MIR inlining leaf functions by default #81079
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
The head ref may contain hidden characters: "inline-\u{1F340}"
Closed
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
7f55f07
Inline trivial implementation of std::iter::Empty
tmiasko b7e28e3
Make arithmetic overflow in step implementations conditional
tmiasko cf78d93
Disable inlining without a warining when coverage is enabled
tmiasko f0f5e19
Inline trivial leaf functions
lcnr 27f7c24
Disable MIR optimizations in inline-hint test
tmiasko 2278495
Use nearest non-inlined scope for as lint root in const prop
tmiasko 639c1ff
Remove locals used only by debuginfo at opt-level=3
tmiasko c30cffd
Disable call terminator validation
tmiasko aefc721
Make polymorphization tests independent of MIR inlining
tmiasko 3d43b90
Make instantiation limit test independent of MIR inlining
tmiasko File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
use rustc_attr as attr; | ||
use rustc_hir as hir; | ||
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}; | ||
|
@@ -37,10 +38,6 @@ struct CallSite<'tcx> { | |
|
||
impl<'tcx> MirPass<'tcx> for Inline { | ||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | ||
if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { | ||
return; | ||
} | ||
|
||
if tcx.sess.opts.debugging_opts.instrument_coverage { | ||
// Since `Inline` happens after `InstrumentCoverage`, the function-specific coverage | ||
// counters can be invalidated, such as by merging coverage counter statements from | ||
|
@@ -50,6 +47,13 @@ impl<'tcx> MirPass<'tcx> for Inline { | |
return; | ||
} | ||
|
||
if body.generator_kind.is_some() { | ||
// Avoid inlining into generators, since their `optimized_mir` is used for layout | ||
// computation, which can create a cycle, even when no attempt is made to inline | ||
// the function in the other direction. | ||
return; | ||
} | ||
|
||
if inline(tcx, body) { | ||
debug!("running simplify cfg on {:?}", body.source); | ||
CfgSimplifier::new(body).simplify(); | ||
|
@@ -104,7 +108,7 @@ impl Inliner<'tcx> { | |
Some(it) => it, | ||
}; | ||
|
||
if !self.is_mir_available(&callsite.callee, caller_body) { | ||
if !self.is_mir_available(&callsite.callee) { | ||
debug!("MIR unavailable {}", callsite.callee); | ||
continue; | ||
} | ||
|
@@ -137,11 +141,27 @@ impl Inliner<'tcx> { | |
} | ||
} | ||
|
||
fn is_mir_available(&self, callee: &Instance<'tcx>, caller_body: &Body<'tcx>) -> bool { | ||
if let InstanceDef::Item(_) = callee.def { | ||
if !self.tcx.is_mir_available(callee.def_id()) { | ||
return false; | ||
} | ||
fn is_mir_available(&self, callee: &Instance<'tcx>) -> bool { | ||
match callee.def { | ||
InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) => return false, | ||
|
||
InstanceDef::VtableShim(..) | ||
| InstanceDef::ReifyShim(..) | ||
| InstanceDef::FnPtrShim(..) | ||
| InstanceDef::ClosureOnceShim { .. } | ||
| InstanceDef::DropGlue(..) | ||
| InstanceDef::CloneShim(..) => return true, | ||
|
||
InstanceDef::Item(_) => {} | ||
}; | ||
|
||
if !self.tcx.is_mir_available(callee.def_id()) { | ||
return false; | ||
} | ||
|
||
if self.tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { | ||
// Only inline trivial functions by default. | ||
return self.tcx.is_trivial_mir(callee.def_id()); | ||
} | ||
|
||
if let Some(callee_def_id) = callee.def_id().as_local() { | ||
|
@@ -153,9 +173,7 @@ impl Inliner<'tcx> { | |
// since their `optimized_mir` is used for layout computation, which can | ||
// create a cycle, even when no attempt is made to inline the function | ||
// in the other direction. | ||
!self.tcx.dep_graph.is_fully_enabled() | ||
&& self.hir_id < callee_hir_id | ||
&& caller_body.generator_kind.is_none() | ||
!self.tcx.dep_graph.is_fully_enabled() && self.hir_id < callee_hir_id | ||
} else { | ||
// This cannot result in a cycle since the callee MIR is from another crate | ||
// and is already optimized. | ||
|
@@ -885,3 +903,48 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { | |
} | ||
} | ||
} | ||
|
||
pub fn is_trivial_mir(tcx: TyCtxt<'tcx>, did: DefId) -> bool { | ||
debug!("is_trivial_mir({:?})", did); | ||
if tcx.is_constructor(did) { | ||
debug!("is_trivial_mir = true (constructor)"); | ||
return true; | ||
} | ||
|
||
use rustc_hir::def::DefKind; | ||
if !matches!(tcx.def_kind(did), DefKind::Fn | DefKind::AssocFn) { | ||
debug!("is_trivial_mir = false (not a function)"); | ||
// Only inline functions, don't look at constants here. | ||
return false; | ||
} | ||
|
||
if !did.is_local() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is unreachable. In decoding we just store |
||
// This branch is only taken if no `optimized_mir` is available for | ||
// an extern crate, as `is_trivial_mir` has otherwise been encoded. | ||
debug!("is_trivial_mir = false (no MIR available)"); | ||
return false; | ||
}; | ||
|
||
let body = tcx | ||
.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did.expect_local())) | ||
.borrow(); | ||
|
||
for bb in body.basic_blocks() { | ||
let terminator = bb.terminator(); | ||
if let TerminatorKind::Call { func, .. } = &terminator.kind { | ||
let func_ty = func.ty(body.local_decls(), tcx); | ||
if let ty::FnDef(..) = *func_ty.kind() { | ||
let fn_sig = func_ty.fn_sig(tcx); | ||
if fn_sig.abi() == Abi::RustIntrinsic || fn_sig.abi() == Abi::PlatformIntrinsic { | ||
continue; | ||
} | ||
} | ||
|
||
debug!("is_trivial_mir = false (function call)"); | ||
return false; | ||
} | ||
} | ||
|
||
debug!("is_trivial_mir = true"); | ||
true | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could really use a more semantic name. A "trivial" can mean many things, and what it means in this context is not really specified.
Given that its purpose is to check that the body is trivially inlineable, a name for your consideration:
is_trivially_inlineable
or perhapsis_leaf_mir
.