Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 23adf9f

Browse files
committedFeb 5, 2021
Auto merge of #81215 - cjgillot:defkey-mir, r=oli-obk
Encode MIR metadata by iterating on DefId instead of traversing the HIR tree Split out of #80347. This part only traverses `mir_keys` and encodes MIR according to the def kind. r? `@oli-obk`
2 parents 5605b5d + 09ac459 commit 23adf9f

File tree

1 file changed

+103
-215
lines changed

1 file changed

+103
-215
lines changed
 

‎compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 103 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
22
use crate::rmeta::*;
33

44
use rustc_data_structures::fingerprint::{Fingerprint, FingerprintEncoder};
5-
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
5+
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
66
use rustc_data_structures::stable_hasher::StableHasher;
7-
use rustc_data_structures::sync::{join, Lrc};
7+
use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
88
use rustc_hir as hir;
99
use rustc_hir::def::{CtorOf, DefKind};
1010
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1111
use rustc_hir::definitions::DefPathData;
1212
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
13-
use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
13+
use rustc_hir::itemlikevisit::ItemLikeVisitor;
1414
use rustc_hir::lang_items;
1515
use rustc_hir::{AnonConst, GenericParamKind};
1616
use rustc_index::bit_set::GrowableBitSet;
@@ -65,11 +65,6 @@ pub(super) struct EncodeContext<'a, 'tcx> {
6565
required_source_files: Option<GrowableBitSet<usize>>,
6666
is_proc_macro: bool,
6767
hygiene_ctxt: &'a HygieneEncodeContext,
68-
69-
// Determines if MIR used for code generation will be included in the crate
70-
// metadata. When emitting only metadata (e.g., cargo check), we can avoid
71-
// generating optimized MIR altogether.
72-
emit_codegen_mir: bool,
7368
}
7469

7570
/// If the current crate is a proc-macro, returns early with `Lazy:empty()`.
@@ -580,6 +575,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
580575
// Encode the items.
581576
i = self.position();
582577
self.encode_def_ids();
578+
self.encode_mir();
583579
self.encode_info_for_items();
584580
let item_bytes = self.position() - i;
585581

@@ -785,6 +781,53 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
785781
}
786782
}
787783

784+
/// Whether we should encode MIR.
785+
///
786+
/// Computing, optimizing and encoding the MIR is a relatively expensive operation.
787+
/// We want to avoid this work when not required. Therefore:
788+
/// - we only compute `mir_for_ctfe` on items with const-eval semantics;
789+
/// - we skip `optimized_mir` for check runs.
790+
///
791+
/// Return a pair, resp. for CTFE and for LLVM.
792+
fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
793+
match tcx.def_kind(def_id) {
794+
// Constructors
795+
DefKind::Ctor(_, _) => {
796+
let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
797+
|| tcx.sess.opts.debugging_opts.always_encode_mir;
798+
(true, mir_opt_base)
799+
}
800+
// Constants
801+
DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
802+
(true, false)
803+
}
804+
// Full-fledged functions
805+
DefKind::AssocFn | DefKind::Fn => {
806+
let generics = tcx.generics_of(def_id);
807+
let needs_inline = (generics.requires_monomorphization(tcx)
808+
|| tcx.codegen_fn_attrs(def_id).requests_inline())
809+
&& tcx.sess.opts.output_types.should_codegen();
810+
// Only check the presence of the `const` modifier.
811+
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id());
812+
let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
813+
(is_const_fn, needs_inline || always_encode_mir)
814+
}
815+
// Closures can't be const fn.
816+
DefKind::Closure => {
817+
let generics = tcx.generics_of(def_id);
818+
let needs_inline = (generics.requires_monomorphization(tcx)
819+
|| tcx.codegen_fn_attrs(def_id).requests_inline())
820+
&& tcx.sess.opts.output_types.should_codegen();
821+
let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
822+
(false, needs_inline || always_encode_mir)
823+
}
824+
// Generators require optimized MIR to compute layout.
825+
DefKind::Generator => (false, true),
826+
// The others don't have MIR.
827+
_ => (false, false),
828+
}
829+
}
830+
788831
impl EncodeContext<'a, 'tcx> {
789832
fn encode_def_ids(&mut self) {
790833
if self.is_proc_macro {
@@ -882,11 +925,6 @@ impl EncodeContext<'a, 'tcx> {
882925
self.encode_generics(def_id);
883926
self.encode_explicit_predicates(def_id);
884927
self.encode_inferred_outlives(def_id);
885-
let opt_mir = tcx.sess.opts.debugging_opts.always_encode_mir || self.emit_codegen_mir;
886-
if opt_mir {
887-
self.encode_optimized_mir(def_id.expect_local());
888-
}
889-
self.encode_mir_for_ctfe(def_id.expect_local());
890928
}
891929

892930
fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>) {
@@ -972,11 +1010,6 @@ impl EncodeContext<'a, 'tcx> {
9721010
self.encode_generics(def_id);
9731011
self.encode_explicit_predicates(def_id);
9741012
self.encode_inferred_outlives(def_id);
975-
let opt_mir = tcx.sess.opts.debugging_opts.always_encode_mir || self.emit_codegen_mir;
976-
if opt_mir {
977-
self.encode_optimized_mir(def_id.expect_local());
978-
}
979-
self.encode_mir_for_ctfe(def_id.expect_local());
9801013
}
9811014

9821015
fn encode_generics(&mut self, def_id: DefId) {
@@ -1082,34 +1115,6 @@ impl EncodeContext<'a, 'tcx> {
10821115
self.encode_generics(def_id);
10831116
self.encode_explicit_predicates(def_id);
10841117
self.encode_inferred_outlives(def_id);
1085-
1086-
// This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
1087-
match trait_item.kind {
1088-
ty::AssocKind::Type => {}
1089-
ty::AssocKind::Const => {
1090-
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
1091-
self.encode_mir_for_ctfe(def_id.expect_local());
1092-
self.encode_promoted_mir(def_id.expect_local());
1093-
}
1094-
}
1095-
ty::AssocKind::Fn => {
1096-
let opt_mir =
1097-
tcx.sess.opts.debugging_opts.always_encode_mir || self.emit_codegen_mir;
1098-
if opt_mir {
1099-
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
1100-
self.encode_optimized_mir(def_id.expect_local());
1101-
self.encode_promoted_mir(def_id.expect_local());
1102-
}
1103-
}
1104-
}
1105-
}
1106-
}
1107-
1108-
fn should_encode_fn_opt_mir(&self, def_id: DefId) -> bool {
1109-
self.tcx.sess.opts.debugging_opts.always_encode_mir
1110-
|| (self.emit_codegen_mir
1111-
&& (self.tcx.generics_of(def_id).requires_monomorphization(self.tcx)
1112-
|| self.tcx.codegen_fn_attrs(def_id).requests_inline()))
11131118
}
11141119

11151120
fn encode_info_for_impl_item(&mut self, def_id: DefId) {
@@ -1171,27 +1176,6 @@ impl EncodeContext<'a, 'tcx> {
11711176
self.encode_generics(def_id);
11721177
self.encode_explicit_predicates(def_id);
11731178
self.encode_inferred_outlives(def_id);
1174-
1175-
// The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
1176-
1177-
let (mir, mir_const) = match ast_item.kind {
1178-
hir::ImplItemKind::Const(..) => (false, true),
1179-
hir::ImplItemKind::Fn(ref sig, _) => {
1180-
let opt_mir = self.should_encode_fn_opt_mir(def_id);
1181-
let is_const_fn = sig.header.constness == hir::Constness::Const;
1182-
(opt_mir, is_const_fn)
1183-
}
1184-
hir::ImplItemKind::TyAlias(..) => (false, false),
1185-
};
1186-
if mir {
1187-
self.encode_optimized_mir(def_id.expect_local());
1188-
}
1189-
if mir || mir_const {
1190-
self.encode_promoted_mir(def_id.expect_local());
1191-
}
1192-
if mir_const {
1193-
self.encode_mir_for_ctfe(def_id.expect_local());
1194-
}
11951179
}
11961180

11971181
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
@@ -1202,34 +1186,48 @@ impl EncodeContext<'a, 'tcx> {
12021186
self.lazy(param_names.iter())
12031187
}
12041188

1205-
fn encode_mir_for_ctfe(&mut self, def_id: LocalDefId) {
1206-
debug!("EntryBuilder::encode_mir_for_ctfe({:?})", def_id);
1207-
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
1208-
1209-
let unused = self.tcx.unused_generic_params(def_id);
1210-
if !unused.is_empty() {
1211-
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
1189+
fn encode_mir(&mut self) {
1190+
if self.is_proc_macro {
1191+
return;
12121192
}
12131193

1214-
let abstract_const = self.tcx.mir_abstract_const(def_id);
1215-
if let Ok(Some(abstract_const)) = abstract_const {
1216-
record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
1217-
}
1218-
}
1194+
let mut keys_and_jobs = self
1195+
.tcx
1196+
.mir_keys(LOCAL_CRATE)
1197+
.iter()
1198+
.filter_map(|&def_id| {
1199+
let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id);
1200+
if encode_const || encode_opt {
1201+
Some((def_id, encode_const, encode_opt))
1202+
} else {
1203+
None
1204+
}
1205+
})
1206+
.collect::<Vec<_>>();
1207+
// Sort everything to ensure a stable order for diagnotics.
1208+
keys_and_jobs.sort_by_key(|&(def_id, _, _)| def_id);
1209+
for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() {
1210+
debug_assert!(encode_const || encode_opt);
12191211

1220-
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
1221-
debug!("EntryBuilder::encode_optimized_mir({:?})", def_id);
1222-
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
1212+
debug!("EntryBuilder::encode_mir({:?})", def_id);
1213+
if encode_opt {
1214+
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
1215+
}
1216+
if encode_const {
1217+
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
12231218

1224-
let unused = self.tcx.unused_generic_params(def_id);
1225-
if !unused.is_empty() {
1226-
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
1227-
}
1228-
}
1219+
let abstract_const = self.tcx.mir_abstract_const(def_id);
1220+
if let Ok(Some(abstract_const)) = abstract_const {
1221+
record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
1222+
}
1223+
}
1224+
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
12291225

1230-
fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
1231-
debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
1232-
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
1226+
let unused = self.tcx.unused_generic_params(def_id);
1227+
if !unused.is_empty() {
1228+
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
1229+
}
1230+
}
12331231
}
12341232

12351233
// Encodes the inherent implementations of a structure, enumeration, or trait.
@@ -1487,28 +1485,6 @@ impl EncodeContext<'a, 'tcx> {
14871485
}
14881486
_ => {}
14891487
}
1490-
1491-
// The following part should be kept in sync with `PrefetchVisitor.visit_item`.
1492-
1493-
let (mir, const_mir) = match item.kind {
1494-
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => (false, true),
1495-
hir::ItemKind::Fn(ref sig, ..) => {
1496-
let opt_mir = self.should_encode_fn_opt_mir(def_id);
1497-
let is_const_fn = sig.header.constness == hir::Constness::Const;
1498-
// We don't need the optimized MIR for const fns.
1499-
(opt_mir, is_const_fn)
1500-
}
1501-
_ => (false, false),
1502-
};
1503-
if mir {
1504-
self.encode_optimized_mir(def_id.expect_local());
1505-
}
1506-
if mir || const_mir {
1507-
self.encode_promoted_mir(def_id.expect_local());
1508-
}
1509-
if const_mir {
1510-
self.encode_mir_for_ctfe(def_id.expect_local());
1511-
}
15121488
}
15131489

15141490
/// Serialize the text of exported macros
@@ -1550,14 +1526,6 @@ impl EncodeContext<'a, 'tcx> {
15501526
record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig());
15511527
}
15521528
self.encode_generics(def_id.to_def_id());
1553-
let opt_mir = // FIXME: Optimized MIR is necessary to determine the layout of generators.
1554-
matches!(ty.kind(), ty::Generator(..))
1555-
|| self.tcx.sess.opts.debugging_opts.always_encode_mir
1556-
|| self.emit_codegen_mir;
1557-
if opt_mir {
1558-
self.encode_optimized_mir(def_id);
1559-
self.encode_promoted_mir(def_id);
1560-
}
15611529
}
15621530

15631531
fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
@@ -1572,8 +1540,6 @@ impl EncodeContext<'a, 'tcx> {
15721540
self.encode_generics(def_id.to_def_id());
15731541
self.encode_explicit_predicates(def_id.to_def_id());
15741542
self.encode_inferred_outlives(def_id.to_def_id());
1575-
self.encode_mir_for_ctfe(def_id);
1576-
self.encode_promoted_mir(def_id);
15771543
}
15781544

15791545
fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> {
@@ -2038,90 +2004,25 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
20382004

20392005
/// Used to prefetch queries which will be needed later by metadata encoding.
20402006
/// Only a subset of the queries are actually prefetched to keep this code smaller.
2041-
struct PrefetchVisitor<'tcx> {
2042-
tcx: TyCtxt<'tcx>,
2043-
mir_keys: &'tcx FxHashSet<LocalDefId>,
2044-
}
2045-
2046-
impl<'tcx> PrefetchVisitor<'tcx> {
2047-
fn prefetch_ctfe_mir(&self, def_id: LocalDefId) {
2048-
if self.mir_keys.contains(&def_id) {
2049-
self.tcx.ensure().mir_for_ctfe(def_id);
2050-
self.tcx.ensure().promoted_mir(def_id);
2051-
}
2052-
}
2053-
fn prefetch_mir(&self, def_id: LocalDefId) {
2054-
if self.mir_keys.contains(&def_id) {
2055-
self.tcx.ensure().optimized_mir(def_id);
2056-
self.tcx.ensure().promoted_mir(def_id);
2057-
}
2007+
fn prefetch_mir(tcx: TyCtxt<'_>) {
2008+
if !tcx.sess.opts.output_types.should_codegen() {
2009+
// We won't emit MIR, so don't prefetch it.
2010+
return;
20582011
}
2059-
}
20602012

2061-
impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
2062-
fn visit_item(&self, item: &hir::Item<'_>) {
2063-
// This should be kept in sync with `encode_info_for_item`.
2064-
let tcx = self.tcx;
2065-
match item.kind {
2066-
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
2067-
self.prefetch_ctfe_mir(tcx.hir().local_def_id(item.hir_id))
2068-
}
2069-
hir::ItemKind::Fn(ref sig, ..) => {
2070-
let def_id = tcx.hir().local_def_id(item.hir_id);
2071-
let opt_mir = tcx.generics_of(def_id.to_def_id()).requires_monomorphization(tcx)
2072-
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
2073-
if opt_mir {
2074-
self.prefetch_mir(def_id)
2075-
}
2076-
if sig.header.constness == hir::Constness::Const {
2077-
self.prefetch_ctfe_mir(def_id);
2078-
}
2079-
}
2080-
_ => (),
2081-
}
2082-
}
2013+
par_iter(tcx.mir_keys(LOCAL_CRATE)).for_each(|&def_id| {
2014+
let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
20832015

2084-
fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
2085-
// This should be kept in sync with `encode_info_for_trait_item`.
2086-
let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
2087-
match trait_item.kind {
2088-
hir::TraitItemKind::Type(..) => {}
2089-
hir::TraitItemKind::Const(..) => {
2090-
self.prefetch_ctfe_mir(def_id);
2091-
}
2092-
hir::TraitItemKind::Fn(..) => {
2093-
self.prefetch_mir(def_id);
2094-
}
2016+
if encode_const {
2017+
tcx.ensure().mir_for_ctfe(def_id);
20952018
}
2096-
}
2097-
2098-
fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
2099-
// This should be kept in sync with `encode_info_for_impl_item`.
2100-
let tcx = self.tcx;
2101-
match impl_item.kind {
2102-
hir::ImplItemKind::Const(..) => {
2103-
self.prefetch_ctfe_mir(tcx.hir().local_def_id(impl_item.hir_id))
2104-
}
2105-
hir::ImplItemKind::Fn(ref sig, _) => {
2106-
let def_id = tcx.hir().local_def_id(impl_item.hir_id);
2107-
let opt_mir = tcx.generics_of(def_id.to_def_id()).requires_monomorphization(tcx)
2108-
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
2109-
let is_const_fn = sig.header.constness == hir::Constness::Const;
2110-
if opt_mir {
2111-
self.prefetch_mir(def_id)
2112-
}
2113-
if is_const_fn {
2114-
self.prefetch_ctfe_mir(def_id);
2115-
}
2116-
}
2117-
hir::ImplItemKind::TyAlias(..) => (),
2019+
if encode_opt {
2020+
tcx.ensure().optimized_mir(def_id);
21182021
}
2119-
}
2120-
2121-
fn visit_foreign_item(&self, _foreign_item: &'v hir::ForeignItem<'v>) {
2122-
// This should be kept in sync with `encode_info_for_foreign_item`.
2123-
// Foreign items contain no MIR.
2124-
}
2022+
if encode_opt || encode_const {
2023+
tcx.ensure().promoted_mir(def_id);
2024+
}
2025+
})
21252026
}
21262027

21272028
// NOTE(eddyb) The following comment was preserved for posterity, even
@@ -2161,19 +2062,7 @@ pub(super) fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
21612062
// Prefetch some queries used by metadata encoding.
21622063
// This is not necessary for correctness, but is only done for performance reasons.
21632064
// It can be removed if it turns out to cause trouble or be detrimental to performance.
2164-
join(
2165-
|| {
2166-
if !tcx.sess.opts.output_types.should_codegen() {
2167-
// We won't emit MIR, so don't prefetch it.
2168-
return;
2169-
}
2170-
tcx.hir().krate().par_visit_all_item_likes(&PrefetchVisitor {
2171-
tcx,
2172-
mir_keys: tcx.mir_keys(LOCAL_CRATE),
2173-
});
2174-
},
2175-
|| tcx.exported_symbols(LOCAL_CRATE),
2176-
);
2065+
join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE));
21772066
},
21782067
)
21792068
.0
@@ -2206,7 +2095,6 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
22062095
required_source_files,
22072096
is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro),
22082097
hygiene_ctxt: &hygiene_ctxt,
2209-
emit_codegen_mir: tcx.sess.opts.output_types.should_codegen(),
22102098
};
22112099

22122100
// Encode the rustc version string in a predictable location.

0 commit comments

Comments
 (0)
Please sign in to comment.