Encode only MIR that can be used by 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:
parent
01ce2d0ea1
commit
d99333e444
@ -14,7 +14,8 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
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::lang_items::LangItem;
|
||||
@ -50,7 +51,6 @@ pub(super) struct EncodeContext<'a, 'tcx> {
|
||||
opaque: opaque::FileEncoder,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
feat: &'tcx rustc_feature::Features,
|
||||
|
||||
tables: TableBuilders,
|
||||
|
||||
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.
|
||||
/// We want to avoid this work when not required. Therefore:
|
||||
/// - we only compute `mir_for_ctfe` on items with const-eval semantics;
|
||||
/// - 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.
|
||||
fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
||||
/// Note: Reachable set describes definitions that might be generated or referenced from other
|
||||
/// 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) {
|
||||
// Constructors
|
||||
DefKind::Ctor(_, _) => {
|
||||
@ -1027,14 +1043,15 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
||||
// Full-fledged functions + closures
|
||||
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let needs_inline = (generics.requires_monomorphization(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id).requests_inline())
|
||||
&& tcx.sess.opts.output_types.should_codegen();
|
||||
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
|
||||
|| (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]`.
|
||||
let is_const_fn = tcx.is_const_fn_raw(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, needs_inline || always_encode_mir)
|
||||
(is_const_fn, opt)
|
||||
}
|
||||
// Generators require optimized MIR to compute layout.
|
||||
DefKind::Generator => (false, true),
|
||||
@ -1580,9 +1597,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
let tcx = self.tcx;
|
||||
let reachable_set = tcx.reachable_set(());
|
||||
|
||||
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 }
|
||||
});
|
||||
for (def_id, encode_const, encode_opt) in keys_and_jobs {
|
||||
@ -2067,8 +2085,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
|
||||
return;
|
||||
}
|
||||
|
||||
let reachable_set = tcx.reachable_set(());
|
||||
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 {
|
||||
tcx.ensure_with_value().mir_for_ctfe(def_id);
|
||||
|
@ -90,6 +90,10 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
|
||||
.typeck_results()
|
||||
.type_dependent_def(expr.hir_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,
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,7 @@ use core::num::flt2dec;
|
||||
use std::fmt::{Formatter, Result};
|
||||
|
||||
// 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
|
||||
T: flt2dec::DecodableFloat,
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user