diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 9f34aee1947cd..4365c436fe494 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -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}; @@ -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) } #[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) } }; } diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 8aea9a9f58850..43657be481396 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -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 diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 10b89cdd15a52..20ae2dcbde336 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -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) } diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 6723e236a1fe9..62cbea8d74d1f 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -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); diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 1c287be9f6bbc..935d24e50eaa1 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -283,6 +283,7 @@ define_tables! { // Also, as an optimization, a missing entry indicates an empty `&[]`. inferred_outlives: Table, Span)])>, super_predicates: Table)>, + is_trivial_mir: Table>, mir: Table)>, promoted_mir: Table>)>, unused_generic_params: Table>>, diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index a8f6723a35605..ae61093199fc5 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -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> { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 92ea162e419db..881eec0c2d69a 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -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- @@ -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()); @@ -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 + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 3803ee78fd4d9..aec1b9e952321 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -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, @@ -510,6 +511,8 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) 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);