Skip to content

Commit fdf29c5

Browse files
committed
Auto merge of rust-lang#123488 - oli-obk:required_items_query, r=<try>
Create a separate query for required and mentioned items instead of tracking them in the MIR body implements rust-lang#122862 (comment) May permit further improvements without sacrificing perf... iff this PR isn't horrible for perf 🙃
2 parents ea40fa2 + 27f29d1 commit fdf29c5

File tree

27 files changed

+662
-153
lines changed

27 files changed

+662
-153
lines changed

compiler/rustc_const_eval/src/interpret/eval_context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
823823

824824
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
825825
if M::POST_MONO_CHECKS {
826-
for &const_ in &body.required_consts {
826+
for &const_ in &self.tcx.required_and_mentioned_items(instance.def).required_consts {
827827
let c = self
828828
.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
829829
c.eval(*self.tcx, self.param_env, const_.span).map_err(|err| {

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+9
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,15 @@ provide! { tcx, def_id, other, cdata,
222222
object_lifetime_default => { table }
223223
thir_abstract_const => { table }
224224
optimized_mir => { table }
225+
required_and_mentioned_items_of_item => {
226+
cdata
227+
.root
228+
.tables
229+
.required_and_mentioned_items_of_item
230+
.get(cdata, def_id.index)
231+
.map(|lazy| lazy.decode((cdata, tcx)))
232+
.unwrap_or_default()
233+
}
225234
mir_for_ctfe => { table }
226235
closure_saved_names_of_captured_variables => { table }
227236
mir_coroutine_witnesses => { table }

compiler/rustc_metadata/src/rmeta/encoder.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::definitions::DefPathData;
1212
use rustc_hir_pretty::id_to_string;
1313
use rustc_middle::middle::dependency_format::Linkage;
1414
use rustc_middle::middle::exported_symbols::metadata_symbol_name;
15-
use rustc_middle::mir::interpret;
15+
use rustc_middle::mir::{interpret, RequiredAndMentionedItems};
1616
use rustc_middle::query::LocalCrate;
1717
use rustc_middle::query::Providers;
1818
use rustc_middle::traits::specialization_graph;
@@ -1648,6 +1648,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
16481648
for (def_id, encode_const, encode_opt) in keys_and_jobs {
16491649
debug_assert!(encode_const || encode_opt);
16501650

1651+
let items = tcx.required_and_mentioned_items_of_item(def_id);
1652+
let RequiredAndMentionedItems { required_consts, mentioned_items } = items;
1653+
if !required_consts.is_empty() || !mentioned_items.is_empty() {
1654+
record!(self.tables.required_and_mentioned_items_of_item[def_id.to_def_id()] <- items);
1655+
}
1656+
16511657
debug!("EntryBuilder::encode_mir({:?})", def_id);
16521658
if encode_opt {
16531659
record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ define_tables! {
428428
const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<rustc_middle::ty::Const<'static>>>>,
429429
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
430430
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
431+
required_and_mentioned_items_of_item: Table<DefIndex, LazyValue<mir::RequiredAndMentionedItems<'static>>>,
431432
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
432433
closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>,
433434
mir_coroutine_witnesses: Table<DefIndex, LazyValue<mir::CoroutineLayout<'static>>>,

compiler/rustc_middle/src/mir/mod.rs

+2-40
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use rustc_hir::{
2222
ImplicitSelfKind,
2323
};
2424
use rustc_session::Session;
25-
use rustc_span::source_map::Spanned;
2625
use rustc_target::abi::{FieldIdx, VariantIdx};
2726

2827
use polonius_engine::Atom;
@@ -61,6 +60,7 @@ pub mod mono;
6160
pub mod patch;
6261
pub mod pretty;
6362
mod query;
63+
mod required_items;
6464
mod statement;
6565
mod syntax;
6666
pub mod tcx;
@@ -77,6 +77,7 @@ pub use self::pretty::{
7777
};
7878
pub use consts::*;
7979
use pretty::pretty_print_const_value;
80+
pub use required_items::{MentionedItem, RequiredAndMentionedItems};
8081
pub use statement::*;
8182
pub use syntax::*;
8283
pub use terminator::*;
@@ -308,21 +309,6 @@ impl<'tcx> CoroutineInfo<'tcx> {
308309
}
309310
}
310311

311-
/// Some item that needs to monomorphize successfully for a MIR body to be considered well-formed.
312-
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable, TyEncodable, TyDecodable)]
313-
#[derive(TypeFoldable, TypeVisitable)]
314-
pub enum MentionedItem<'tcx> {
315-
/// A function that gets called. We don't necessarily know its precise type yet, since it can be
316-
/// hidden behind a generic.
317-
Fn(Ty<'tcx>),
318-
/// A type that has its drop shim called.
319-
Drop(Ty<'tcx>),
320-
/// Unsizing casts might require vtables, so we have to record them.
321-
UnsizeCast { source_ty: Ty<'tcx>, target_ty: Ty<'tcx> },
322-
/// A closure that is coerced to a function pointer.
323-
Closure(Ty<'tcx>),
324-
}
325-
326312
/// The lowered representation of a single function.
327313
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
328314
pub struct Body<'tcx> {
@@ -384,26 +370,6 @@ pub struct Body<'tcx> {
384370
/// A span representing this MIR, for error reporting.
385371
pub span: Span,
386372

387-
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
388-
/// We hold in this field all the constants we are not able to evaluate yet.
389-
///
390-
/// This is soundness-critical, we make a guarantee that all consts syntactically mentioned in a
391-
/// function have successfully evaluated if the function ever gets executed at runtime.
392-
pub required_consts: Vec<ConstOperand<'tcx>>,
393-
394-
/// Further items that were mentioned in this function and hence *may* become monomorphized,
395-
/// depending on optimizations. We use this to avoid optimization-dependent compile errors: the
396-
/// collector recursively traverses all "mentioned" items and evaluates all their
397-
/// `required_consts`.
398-
///
399-
/// This is *not* soundness-critical and the contents of this list are *not* a stable guarantee.
400-
/// All that's relevant is that this set is optimization-level-independent, and that it includes
401-
/// everything that the collector would consider "used". (For example, we currently compute this
402-
/// set after drop elaboration, so some drop calls that can never be reached are not considered
403-
/// "mentioned".) See the documentation of `CollectionMode` in
404-
/// `compiler/rustc_monomorphize/src/collector.rs` for more context.
405-
pub mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>,
406-
407373
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
408374
///
409375
/// Note that this does not actually mean that this body is not computable right now.
@@ -479,8 +445,6 @@ impl<'tcx> Body<'tcx> {
479445
spread_arg: None,
480446
var_debug_info,
481447
span,
482-
required_consts: Vec::new(),
483-
mentioned_items: Vec::new(),
484448
is_polymorphic: false,
485449
injection_phase: None,
486450
tainted_by_errors,
@@ -509,8 +473,6 @@ impl<'tcx> Body<'tcx> {
509473
arg_count: 0,
510474
spread_arg: None,
511475
span: DUMMY_SP,
512-
required_consts: Vec::new(),
513-
mentioned_items: Vec::new(),
514476
var_debug_info: Vec::new(),
515477
is_polymorphic: false,
516478
injection_phase: None,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use rustc_span::source_map::Spanned;
2+
3+
use crate::ty::{self, Ty, TyCtxt};
4+
5+
use super::ConstOperand;
6+
7+
#[derive(Debug, HashStable, TyEncodable, TyDecodable, Default)]
8+
pub struct RequiredAndMentionedItems<'tcx> {
9+
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
10+
/// We hold in this field all the constants we are not able to evaluate yet.
11+
///
12+
/// This is soundness-critical, we make a guarantee that all consts syntactically mentioned in a
13+
/// function have successfully evaluated if the function ever gets executed at runtime.
14+
pub required_consts: Vec<ConstOperand<'tcx>>,
15+
16+
/// Further items that were mentioned in this function and hence *may* become monomorphized,
17+
/// depending on optimizations. We use this to avoid optimization-dependent compile errors: the
18+
/// collector recursively traverses all "mentioned" items and evaluates all their
19+
/// `required_consts`.
20+
///
21+
/// This is *not* soundness-critical and the contents of this list are *not* a stable guarantee.
22+
/// All that's relevant is that this set is optimization-level-independent, and that it includes
23+
/// everything that the collector would consider "used". (For example, we currently compute this
24+
/// set after drop elaboration, so some drop calls that can never be reached are not considered
25+
/// "mentioned".) See the documentation of `CollectionMode` in
26+
/// `compiler/rustc_monomorphize/src/collector.rs` for more context.
27+
pub mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>,
28+
}
29+
30+
/// Some item that needs to monomorphize successfully for a MIR body to be considered well-formed.
31+
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable, TyEncodable, TyDecodable)]
32+
#[derive(TypeFoldable, TypeVisitable)]
33+
pub enum MentionedItem<'tcx> {
34+
/// A function that gets called. We don't necessarily know its precise type yet, since it can be
35+
/// hidden behind a generic.
36+
Fn(Ty<'tcx>),
37+
/// A type that has its drop shim called.
38+
Drop(Ty<'tcx>),
39+
/// Unsizing casts might require vtables, so we have to record them.
40+
UnsizeCast { source_ty: Ty<'tcx>, target_ty: Ty<'tcx> },
41+
/// A closure that is coerced to a function pointer.
42+
Closure(Ty<'tcx>),
43+
}
44+
45+
impl<'tcx> TyCtxt<'tcx> {
46+
pub fn required_and_mentioned_items(
47+
self,
48+
key: ty::InstanceDef<'tcx>,
49+
) -> &'tcx RequiredAndMentionedItems<'tcx> {
50+
match key {
51+
ty::InstanceDef::Item(id) => self.required_and_mentioned_items_of_item(id),
52+
ty::InstanceDef::Intrinsic(_)
53+
| ty::InstanceDef::VTableShim(_)
54+
| ty::InstanceDef::ReifyShim(..)
55+
| ty::InstanceDef::FnPtrShim(_, _)
56+
| ty::InstanceDef::Virtual(_, _)
57+
| ty::InstanceDef::ClosureOnceShim { .. }
58+
| ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
59+
| ty::InstanceDef::CoroutineKindShim { .. }
60+
| ty::InstanceDef::ThreadLocalShim(_)
61+
| ty::InstanceDef::DropGlue(_, _)
62+
| ty::InstanceDef::CloneShim(_, _)
63+
| ty::InstanceDef::FnPtrAddrShim(_, _) => {
64+
self.required_and_mentioned_items_of_shim(key)
65+
}
66+
}
67+
}
68+
}

compiler/rustc_middle/src/mir/visit.rs

-5
Original file line numberDiff line numberDiff line change
@@ -1050,11 +1050,6 @@ macro_rules! super_body {
10501050
}
10511051

10521052
$self.visit_span($(& $mutability)? $body.span);
1053-
1054-
for const_ in &$($mutability)? $body.required_consts {
1055-
let location = Location::START;
1056-
$self.visit_constant(const_, location);
1057-
}
10581053
}
10591054
}
10601055

compiler/rustc_middle/src/query/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,21 @@ rustc_queries! {
584584
separate_provide_extern
585585
}
586586

587+
/// Cross-crate cache of `required_and_mentioned_items`. Do not call directly.
588+
query required_and_mentioned_items_of_item(key: DefId) -> &'tcx mir::RequiredAndMentionedItems<'tcx> {
589+
desc { |tcx| "computing required and mentioned items for `{}`", tcx.def_path_str(key) }
590+
cache_on_disk_if { key.is_local() }
591+
arena_cache
592+
separate_provide_extern
593+
}
594+
595+
/// Internal implementation detail of `required_and_mentioned_items`. Do not call directly.
596+
query required_and_mentioned_items_of_shim(key: ty::InstanceDef<'tcx>) -> &'tcx mir::RequiredAndMentionedItems<'tcx> {
597+
desc { |tcx| "computing required and mentioned items for `{}`", tcx.def_path_str(key.def_id()) }
598+
cache_on_disk_if { true }
599+
arena_cache
600+
}
601+
587602
/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
588603
/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
589604
/// have had a chance to potentially remove some of them.

compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ macro_rules! parameterized_over_tcx {
126126
parameterized_over_tcx! {
127127
crate::middle::exported_symbols::ExportedSymbol,
128128
crate::mir::Body,
129+
crate::mir::RequiredAndMentionedItems,
129130
crate::mir::CoroutineLayout,
130131
crate::mir::interpret::ConstAllocation,
131132
ty::Ty,

compiler/rustc_mir_build/src/build/custom/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ pub(super) fn build_custom_mir<'tcx>(
5555
spread_arg: None,
5656
var_debug_info: Vec::new(),
5757
span,
58-
required_consts: Vec::new(),
59-
mentioned_items: Vec::new(),
6058
is_polymorphic: false,
6159
tainted_by_errors: None,
6260
injection_phase: None,

compiler/rustc_mir_transform/src/inline.rs

+1-33
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,7 @@ impl<'tcx> Inliner<'tcx> {
566566
mut callee_body: Body<'tcx>,
567567
) {
568568
let terminator = caller_body[callsite.block].terminator.take().unwrap();
569-
let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind
570-
else {
569+
let TerminatorKind::Call { args, destination, unwind, target, .. } = terminator.kind else {
571570
bug!("unexpected terminator kind {:?}", terminator.kind);
572571
};
573572

@@ -706,37 +705,6 @@ impl<'tcx> Inliner<'tcx> {
706705
source_info: callsite.source_info,
707706
kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
708707
});
709-
710-
// Copy only unevaluated constants from the callee_body into the caller_body.
711-
// Although we are only pushing `ConstKind::Unevaluated` consts to
712-
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
713-
// because we are calling `instantiate_and_normalize_erasing_regions`.
714-
caller_body.required_consts.extend(callee_body.required_consts.iter().copied().filter(
715-
|&ct| match ct.const_ {
716-
Const::Ty(_) => {
717-
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
718-
}
719-
Const::Val(..) | Const::Unevaluated(..) => true,
720-
},
721-
));
722-
// Now that we incorporated the callee's `required_consts`, we can remove the callee from
723-
// `mentioned_items` -- but we have to take their `mentioned_items` in return. This does
724-
// some extra work here to save the monomorphization collector work later. It helps a lot,
725-
// since monomorphization can avoid a lot of work when the "mentioned items" are similar to
726-
// the actually used items. By doing this we can entirely avoid visiting the callee!
727-
// We need to reconstruct the `required_item` for the callee so that we can find and
728-
// remove it.
729-
let callee_item = MentionedItem::Fn(func.ty(caller_body, self.tcx));
730-
if let Some(idx) =
731-
caller_body.mentioned_items.iter().position(|item| item.node == callee_item)
732-
{
733-
// We found the callee, so remove it and add its items instead.
734-
caller_body.mentioned_items.remove(idx);
735-
caller_body.mentioned_items.extend(callee_body.mentioned_items);
736-
} else {
737-
// If we can't find the callee, there's no point in adding its items.
738-
// Probably it already got removed by being inlined elsewhere in the same function.
739-
}
740708
}
741709

742710
fn make_call_args(

0 commit comments

Comments
 (0)