collector: recursively traverse 'mentioned' items to evaluate their constants
This commit is contained in:
parent
d31b6fb8c0
commit
712fe36611
24 changed files with 641 additions and 142 deletions
|
@ -565,7 +565,8 @@ impl<'tcx> Inliner<'tcx> {
|
|||
mut callee_body: Body<'tcx>,
|
||||
) {
|
||||
let terminator = caller_body[callsite.block].terminator.take().unwrap();
|
||||
let TerminatorKind::Call { args, destination, unwind, target, .. } = terminator.kind else {
|
||||
let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind
|
||||
else {
|
||||
bug!("unexpected terminator kind {:?}", terminator.kind);
|
||||
};
|
||||
|
||||
|
@ -717,6 +718,30 @@ impl<'tcx> Inliner<'tcx> {
|
|||
Const::Val(..) | Const::Unevaluated(..) => true,
|
||||
},
|
||||
));
|
||||
// Now that we incorporated the callee's `required_consts`, we can remove the callee from
|
||||
// `mentioned_items` -- but we have to take their `mentioned_items` in return. This does
|
||||
// some extra work here to save the monomorphization collector work later. It helps a lot,
|
||||
// since monomorphization can avoid a lot of work when the "mentioned items" are similar to
|
||||
// the actually used items. By doing this we can entirely avoid visiting the callee!
|
||||
let callee_item = {
|
||||
// We need to reconstruct the `required_item` for the callee so that we can find and
|
||||
// remove it.
|
||||
let func_ty = func.ty(caller_body, self.tcx);
|
||||
match func_ty.kind() {
|
||||
ty::FnDef(def_id, args) => MentionedItem::Fn(*def_id, args),
|
||||
_ => bug!(),
|
||||
}
|
||||
};
|
||||
if let Some(idx) =
|
||||
caller_body.mentioned_items.iter().position(|item| item.node == callee_item)
|
||||
{
|
||||
// We found the callee, so remove it and add its items instead.
|
||||
caller_body.mentioned_items.remove(idx);
|
||||
caller_body.mentioned_items.extend(callee_body.mentioned_items);
|
||||
} else {
|
||||
// If we can't find the callee, there's no point in adding its items.
|
||||
// Probably it already got removed by being inlined elsewhere in the same function.
|
||||
}
|
||||
}
|
||||
|
||||
fn make_call_args(
|
||||
|
|
|
@ -89,6 +89,7 @@ mod lint;
|
|||
mod lower_intrinsics;
|
||||
mod lower_slice_len;
|
||||
mod match_branches;
|
||||
mod mentioned_items;
|
||||
mod multiple_return_terminators;
|
||||
mod normalize_array_len;
|
||||
mod nrvo;
|
||||
|
@ -566,6 +567,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
tcx,
|
||||
body,
|
||||
&[
|
||||
// Before doing anything, remember which items are being mentioned so that the set of items
|
||||
// visited does not depend on the optimization level.
|
||||
&mentioned_items::MentionedItems,
|
||||
// Add some UB checks before any UB gets optimized away.
|
||||
&check_alignment::CheckAlignment,
|
||||
// Before inlining: trim down MIR with passes to reduce inlining work.
|
||||
|
||||
|
|
57
compiler/rustc_mir_transform/src/mentioned_items.rs
Normal file
57
compiler/rustc_mir_transform/src/mentioned_items.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{self, ConstOperand, Location, MentionedItem, MirPass};
|
||||
use rustc_middle::ty::{self, 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_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) {
|
||||
let const_ = constant.const_;
|
||||
// This is how function items get referenced: via constants of `FnDef` type. This handles
|
||||
// both functions that are called and those that are just turned to function pointers.
|
||||
if let ty::FnDef(def_id, args) = const_.ty().kind() {
|
||||
debug!("adding to required_items: {def_id:?}");
|
||||
self.mentioned_items
|
||||
.push(Spanned { node: MentionedItem::Fn(*def_id, args), span: constant.span });
|
||||
}
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ use std::iter;
|
|||
|
||||
use crate::{
|
||||
abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
|
||||
pass_manager as pm, remove_noop_landing_pads, simplify,
|
||||
mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify,
|
||||
};
|
||||
use rustc_middle::mir::patch::MirPatch;
|
||||
use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
|
||||
|
@ -147,6 +147,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
|
|||
tcx,
|
||||
&mut body,
|
||||
&[
|
||||
&mentioned_items::MentionedItems,
|
||||
&abort_unwinding_calls::AbortUnwindingCalls,
|
||||
&add_call_guards::CriticalCallEdges,
|
||||
],
|
||||
|
@ -178,6 +179,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
|
|||
tcx,
|
||||
&mut result,
|
||||
&[
|
||||
&mentioned_items::MentionedItems,
|
||||
&add_moves_for_packed_drops::AddMovesForPackedDrops,
|
||||
&deref_separator::Derefer,
|
||||
&remove_noop_landing_pads::RemoveNoopLandingPads,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue