Auto merge of #115306 - tmiasko:encode-reachable-mir, r=cjgillot
Encode only MIR reachable from other crates Only reachable items might participate in the code generation in the downstream crates. Omit redundant optimized MIR of unreachable items from a crate metadata. Additionally, include reachable closures in reachable set, so that unreachable closures can be omitted on the same basis.
This commit is contained in:
commit
7418413a7f
@ -14,7 +14,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{
|
use rustc_hir::def_id::{
|
||||||
CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
|
CrateNum, DefId, DefIndex, LocalDefId, LocalDefIdSet, CRATE_DEF_ID, CRATE_DEF_INDEX,
|
||||||
|
LOCAL_CRATE,
|
||||||
};
|
};
|
||||||
use rustc_hir::definitions::DefPathData;
|
use rustc_hir::definitions::DefPathData;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
@ -50,7 +51,6 @@ pub(super) struct EncodeContext<'a, 'tcx> {
|
|||||||
opaque: opaque::FileEncoder,
|
opaque: opaque::FileEncoder,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
feat: &'tcx rustc_feature::Features,
|
feat: &'tcx rustc_feature::Features,
|
||||||
|
|
||||||
tables: TableBuilders,
|
tables: TableBuilders,
|
||||||
|
|
||||||
lazy_state: LazyState,
|
lazy_state: LazyState,
|
||||||
@ -1002,15 +1002,31 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether we should encode MIR.
|
/// Whether we should encode MIR. Return a pair, resp. for CTFE and for LLVM.
|
||||||
///
|
///
|
||||||
/// Computing, optimizing and encoding the MIR is a relatively expensive operation.
|
/// Computing, optimizing and encoding the MIR is a relatively expensive operation.
|
||||||
/// We want to avoid this work when not required. Therefore:
|
/// We want to avoid this work when not required. Therefore:
|
||||||
/// - we only compute `mir_for_ctfe` on items with const-eval semantics;
|
/// - we only compute `mir_for_ctfe` on items with const-eval semantics;
|
||||||
/// - we skip `optimized_mir` for check runs.
|
/// - we skip `optimized_mir` for check runs.
|
||||||
|
/// - we only encode `optimized_mir` that could be generated in other crates, that is, a code that
|
||||||
|
/// is either generic or has inline hint, and is reachable from the other crates (contained
|
||||||
|
/// in reachable set).
|
||||||
///
|
///
|
||||||
/// Return a pair, resp. for CTFE and for LLVM.
|
/// Note: Reachable set describes definitions that might be generated or referenced from other
|
||||||
fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
/// crates and it can be used to limit optimized MIR that needs to be encoded. On the other hand,
|
||||||
|
/// the reachable set doesn't have much to say about which definitions might be evaluated at compile
|
||||||
|
/// time in other crates, so it cannot be used to omit CTFE MIR. For example, `f` below is
|
||||||
|
/// unreachable and yet it can be evaluated in other crates:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// const fn f() -> usize { 0 }
|
||||||
|
/// pub struct S { pub a: [usize; f()] }
|
||||||
|
/// ```
|
||||||
|
fn should_encode_mir(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
reachable_set: &LocalDefIdSet,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
) -> (bool, bool) {
|
||||||
match tcx.def_kind(def_id) {
|
match tcx.def_kind(def_id) {
|
||||||
// Constructors
|
// Constructors
|
||||||
DefKind::Ctor(_, _) => {
|
DefKind::Ctor(_, _) => {
|
||||||
@ -1027,14 +1043,15 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
|||||||
// Full-fledged functions + closures
|
// Full-fledged functions + closures
|
||||||
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
|
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
let needs_inline = (generics.requires_monomorphization(tcx)
|
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
|
||||||
|| tcx.codegen_fn_attrs(def_id).requests_inline())
|
|| (tcx.sess.opts.output_types.should_codegen()
|
||||||
&& tcx.sess.opts.output_types.should_codegen();
|
&& reachable_set.contains(&def_id)
|
||||||
|
&& (generics.requires_monomorphization(tcx)
|
||||||
|
|| tcx.codegen_fn_attrs(def_id).requests_inline()));
|
||||||
// The function has a `const` modifier or is in a `#[const_trait]`.
|
// The function has a `const` modifier or is in a `#[const_trait]`.
|
||||||
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
|
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
|
||||||
|| tcx.is_const_default_method(def_id.to_def_id());
|
|| tcx.is_const_default_method(def_id.to_def_id());
|
||||||
let always_encode_mir = tcx.sess.opts.unstable_opts.always_encode_mir;
|
(is_const_fn, opt)
|
||||||
(is_const_fn, needs_inline || always_encode_mir)
|
|
||||||
}
|
}
|
||||||
// Generators require optimized MIR to compute layout.
|
// Generators require optimized MIR to compute layout.
|
||||||
DefKind::Generator => (false, true),
|
DefKind::Generator => (false, true),
|
||||||
@ -1580,9 +1597,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
let reachable_set = tcx.reachable_set(());
|
||||||
|
|
||||||
let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| {
|
let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| {
|
||||||
let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
|
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
|
||||||
if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None }
|
if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None }
|
||||||
});
|
});
|
||||||
for (def_id, encode_const, encode_opt) in keys_and_jobs {
|
for (def_id, encode_const, encode_opt) in keys_and_jobs {
|
||||||
@ -2067,8 +2085,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reachable_set = tcx.reachable_set(());
|
||||||
par_for_each_in(tcx.mir_keys(()), |&def_id| {
|
par_for_each_in(tcx.mir_keys(()), |&def_id| {
|
||||||
let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
|
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
|
||||||
|
|
||||||
if encode_const {
|
if encode_const {
|
||||||
tcx.ensure_with_value().mir_for_ctfe(def_id);
|
tcx.ensure_with_value().mir_for_ctfe(def_id);
|
||||||
|
@ -90,6 +90,10 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
|
|||||||
.typeck_results()
|
.typeck_results()
|
||||||
.type_dependent_def(expr.hir_id)
|
.type_dependent_def(expr.hir_id)
|
||||||
.map(|(kind, def_id)| Res::Def(kind, def_id)),
|
.map(|(kind, def_id)| Res::Def(kind, def_id)),
|
||||||
|
hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => {
|
||||||
|
self.reachable_symbols.insert(def_id);
|
||||||
|
None
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use core::num::flt2dec;
|
|||||||
use std::fmt::{Formatter, Result};
|
use std::fmt::{Formatter, Result};
|
||||||
|
|
||||||
// EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff
|
// EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff
|
||||||
fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
|
pub fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
|
||||||
where
|
where
|
||||||
T: flt2dec::DecodableFloat,
|
T: flt2dec::DecodableFloat,
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user