Skip to content
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

always try inlining functions which do not call other functions #75495

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions library/core/src/iter/range.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::char;
use crate::convert::TryFrom;
use crate::mem;
use crate::ops::{self, Add, Sub, Try};
use crate::ops::{self, Try};

use super::{FusedIterator, TrustedLen};

Expand Down Expand Up @@ -201,24 +201,12 @@ macro_rules! step_identical_methods {

#[inline]
fn forward(start: Self, n: usize) -> Self {
// In debug builds, trigger a panic on overflow.
// This should optimize completely out in release builds.
if Self::forward_checked(start, n).is_none() {
let _ = Add::add(Self::MAX, 1);
}
// Do wrapping math to allow e.g. `Step::forward(-128i8, 255)`.
start.wrapping_add(n as Self)
start + (n as Self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intention here was to inherit the user's setting for debug assertion, even when std is compiled in release mode (as it usually is).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, will have to rewrite this again before merging 👍

}

#[inline]
fn backward(start: Self, n: usize) -> Self {
// In debug builds, trigger a panic on overflow.
// This should optimize completely out in release builds.
if Self::backward_checked(start, n).is_none() {
let _ = Sub::sub(Self::MIN, 1);
}
// Do wrapping math to allow e.g. `Step::backward(127i8, 255)`.
start.wrapping_sub(n as Self)
start - (n as Self)
}
};
}
Expand Down
9 changes: 9 additions & 0 deletions src/librustc_metadata/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
}

fn get_is_trivial_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> bool {
self.root
.tables
.is_trivial_mir
.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.map_or(false, |v| v.decode((self, tcx)))
}

fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
self.root
.tables
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
})
}
is_trivial_mir => { *tcx.arena.alloc(cdata.get_is_trivial_mir(tcx, def_id.index)) }
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,7 @@ impl EncodeContext<'a, 'tcx> {
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
debug!("EntryBuilder::encode_mir({:?})", def_id);
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
record!(self.tables.is_trivial_mir[def_id.to_def_id()] <- self.tcx.is_trivial_mir(def_id));
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));

let unused = self.tcx.unused_generic_params(def_id);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_metadata/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ define_tables! {
// Also, as an optimization, a missing entry indicates an empty `&[]`.
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
is_trivial_mir: Table<DefIndex, Lazy<bool>>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_middle/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ rustc_queries! {
}
}

query is_trivial_mir(key: DefId) -> bool {
desc { |tcx| "checking if MIR for `{}` is trivial", tcx.def_path_str(key) }
}

/// MIR after our optimization passes have run. This is MIR that is ready
/// for codegen. This is also the only query that can fetch non-local MIR, at present.
query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
Expand Down
50 changes: 48 additions & 2 deletions src/librustc_mir/transform/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct CallSite<'tcx> {

impl<'tcx> MirPass<'tcx> for Inline {
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
if tcx.sess.opts.debugging_opts.mir_opt_level >= 1 {
if tcx.sess.opts.debugging_opts.instrument_coverage {
// The current implementation of source code coverage injects code region counters
// into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
Expand Down Expand Up @@ -100,7 +100,12 @@ impl Inliner<'tcx> {
continue;
}

let callee_body = if let Some(callee_def_id) = callsite.callee.as_local() {
let callee_body = if self.tcx.is_trivial_mir(callsite.callee) {
self.tcx.optimized_mir(callsite.callee)
} else if self.tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
// Only inline trivial functions by default.
continue;
} else if let Some(callee_def_id) = callsite.callee.as_local() {
let callee_hir_id = self.tcx.hir().as_local_hir_id(callee_def_id);
let self_hir_id =
self.tcx.hir().as_local_hir_id(self.source.def_id().expect_local());
Expand Down Expand Up @@ -802,3 +807,44 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
*scope = self.scope_map[*scope];
}
}

struct FunctionCallFinder {
found: bool,
}

impl FunctionCallFinder {
fn new() -> Self {
FunctionCallFinder { found: false }
}
}

impl<'tcx> Visitor<'tcx> for FunctionCallFinder {
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) {
if let TerminatorKind::Call { .. } = terminator.kind {
self.found = true;
}
}
}

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;
}

if let Some(did) = did.as_local() {
let body = tcx
.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did))
.borrow();
let mut finder = FunctionCallFinder::new();
finder.visit_body(&body);
debug!("is_trivial_mir = {}", !finder.found);
!finder.found
} else {
// 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)");
false
}
}
3 changes: 3 additions & 0 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
},
mir_validated,
mir_drops_elaborated_and_const_checked,
is_trivial_mir: inline::is_trivial_mir,
optimized_mir,
optimized_mir_of_const_arg,
is_mir_available,
Expand Down Expand Up @@ -510,6 +511,8 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>)
return shim::build_adt_ctor(tcx, def.did.to_def_id());
}

// `is_trivial_mir` uses `mir_drops_elaborated_and_const_checked` so run that first.
tcx.ensure().is_trivial_mir(def.did.to_def_id());
let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
run_optimization_passes(tcx, &mut body, def.did, None);

Expand Down