forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#122568 - RalfJung:mentioned-items, r=
recursively evaluate the constants in everything that is 'mentioned' This is another attempt at fixing rust-lang#107503. The previous attempt at rust-lang#112879 seems stuck in figuring out where the [perf regression](https://perf.rust-lang.org/compare.html?start=c55d1ee8d4e3162187214692229a63c2cc5e0f31&end=ec8de1ebe0d698b109beeaaac83e60f4ef8bb7d1&stat=instructions:u) comes from. In rust-lang#122258 I learned some things, which informed the approach this PR is taking. Quoting from the new collector docs, which explain the high-level idea: ```rust //! One important role of collection is to evaluate all constants that are used by all the items //! which are being collected. Codegen can then rely on only encountering constants that evaluate //! successfully, and if a constant fails to evaluate, the collector has much better context to be //! able to show where this constant comes up. //! //! However, the exact set of "used" items (collected as described above), and therefore the exact //! set of used constants, can depend on optimizations. Optimizing away dead code may optimize away //! a function call that uses a failing constant, so an unoptimized build may fail where an //! optimized build succeeds. This is undesirable. //! //! To fix this, the collector has the concept of "mentioned" items. Some time during the MIR //! pipeline, before any optimization-level-dependent optimizations, we compute a list of all items //! that syntactically appear in the code. These are considered "mentioned", and even if they are in //! dead code and get optimized away (which makes them no longer "used"), they are still //! "mentioned". For every used item, the collector ensures that all mentioned items, recursively, //! do not use a failing constant. This is reflected via the [`CollectionMode`], which determines //! whether we are visiting a used item or merely a mentioned item. enum CollectionMode { /// Collect items that are used, i.e., actually needed for codegen. /// /// Which items are used can depend on optimization levels, as MIR optimizations can remove /// uses. UsedItems, /// Collect items that are mentioned. The goal of this mode is that it is independent of /// optimizations: the set of "mentioned" items is computed before optimizations are run. /// /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we /// might decide to run them before computing mentioned items.) The key property of this set is /// that it is optimization-independent. MentionedItems, } ``` Fixes rust-lang#107503
- Loading branch information
Showing
34 changed files
with
949 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use rustc_middle::mir::visit::Visitor; | ||
use rustc_middle::mir::{self, Location, MentionedItem, MirPass}; | ||
use rustc_middle::ty::Ty; | ||
use rustc_middle::ty::{self, adjustment::PointerCoercion, TyCtxt}; | ||
use rustc_session::Session; | ||
use rustc_span::source_map::Spanned; | ||
|
||
pub struct MentionedItems; | ||
|
||
struct MentionedItemsVisitor<'a, 'tcx> { | ||
tcx: TyCtxt<'tcx>, | ||
body: &'a mir::Body<'tcx>, | ||
mentioned_items: &'a mut Vec<Spanned<MentionedItem<'tcx>>>, | ||
} | ||
|
||
impl<'tcx> MirPass<'tcx> for MentionedItems { | ||
fn is_enabled(&self, _sess: &Session) -> bool { | ||
// If this pass is skipped the collector assume that nothing got mentioned! We could | ||
// potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses | ||
// of anything, but that still seems fragile. Furthermore, even debug builds use level 1, so | ||
// special-casing level 0 is just not worth it. | ||
true | ||
} | ||
|
||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { | ||
debug_assert!(body.mentioned_items.is_empty()); | ||
let mut mentioned_items = Vec::new(); | ||
MentionedItemsVisitor { tcx, body, mentioned_items: &mut mentioned_items }.visit_body(body); | ||
body.mentioned_items = mentioned_items; | ||
} | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { | ||
fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: mir::visit::TyContext) { | ||
if let ty::FnDef(def_id, args) = ty.kind() { | ||
debug!("adding to required_items: {def_id:?}"); | ||
self.mentioned_items.push(Spanned { | ||
node: MentionedItem::Fn(*def_id, args), | ||
span: self.body.span_for_ty_context(ty_context), | ||
}); | ||
} | ||
} | ||
|
||
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { | ||
self.super_terminator(terminator, location); | ||
match terminator.kind { | ||
// We don't need to handle `Call` as we already handled all function type operands in | ||
// `visit_constant`. But we do need to handle `Drop`. | ||
mir::TerminatorKind::Drop { place, .. } => { | ||
let ty = place.ty(self.body, self.tcx).ty; | ||
let span = self.body.source_info(location).span; | ||
self.mentioned_items.push(Spanned { node: MentionedItem::Drop(ty), span }); | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { | ||
self.super_rvalue(rvalue, location); | ||
match *rvalue { | ||
// We need to detect unsizing casts that required vtables. | ||
mir::Rvalue::Cast( | ||
mir::CastKind::PointerCoercion(PointerCoercion::Unsize), | ||
ref operand, | ||
target_ty, | ||
) | ||
| mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => { | ||
let span = self.body.source_info(location).span; | ||
self.mentioned_items.push(Spanned { | ||
node: MentionedItem::UnsizeCast { | ||
source_ty: operand.ty(self.body, self.tcx), | ||
target_ty, | ||
}, | ||
span, | ||
}); | ||
} | ||
// Similarly, record closures that are turned into function pointers. | ||
mir::Rvalue::Cast( | ||
mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)), | ||
ref operand, | ||
_, | ||
) => { | ||
let span = self.body.source_info(location).span; | ||
let source_ty = operand.ty(self.body, self.tcx); | ||
match *source_ty.kind() { | ||
ty::Closure(def_id, args) => { | ||
self.mentioned_items | ||
.push(Spanned { node: MentionedItem::Closure(def_id, args), span }); | ||
} | ||
_ => bug!(), | ||
} | ||
} | ||
// Function pointer casts are already handled by `visit_constant` above. | ||
_ => {} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.