diff options
| author | Ralf Jung <post@ralfj.de> | 2024-08-01 14:01:17 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2024-08-01 15:49:25 +0200 |
| commit | 6d312d7bd17598153c018e4879ccaa657eb48853 (patch) | |
| tree | da2168c13c157b8ba48190bc5b6591a76adf5888 /compiler/rustc_mir_transform/src | |
| parent | 70591dc15db32941fe3595fdbf98e58d6975f95e (diff) | |
| download | rust-6d312d7bd17598153c018e4879ccaa657eb48853.tar.gz rust-6d312d7bd17598153c018e4879ccaa657eb48853.zip | |
MIR required_consts, mentioned_items: ensure we do not forget to fill these lists
Diffstat (limited to 'compiler/rustc_mir_transform/src')
| -rw-r--r-- | compiler/rustc_mir_transform/src/inline.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/lib.rs | 36 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/mentioned_items.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/promote_consts.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/required_consts.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/shim.rs | 12 |
6 files changed, 61 insertions, 30 deletions
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 36b2b3b7c44..f30732e6aaf 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -744,8 +744,8 @@ impl<'tcx> Inliner<'tcx> { // Copy required constants from the callee_body into the caller_body. Although we are only // pushing unevaluated consts to `required_consts`, here they may have been evaluated // because we are calling `instantiate_and_normalize_erasing_regions` -- so we filter again. - caller_body.required_consts.extend( - callee_body.required_consts.into_iter().filter(|ct| ct.const_.is_required_const()), + caller_body.required_consts.as_mut().unwrap().extend( + callee_body.required_consts().into_iter().filter(|ct| ct.const_.is_required_const()), ); // 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 @@ -755,12 +755,11 @@ impl<'tcx> Inliner<'tcx> { // We need to reconstruct the `required_item` for the callee so that we can find and // remove it. let callee_item = MentionedItem::Fn(func.ty(caller_body, self.tcx)); - if let Some(idx) = - caller_body.mentioned_items.iter().position(|item| item.node == callee_item) - { + let caller_mentioned_items = caller_body.mentioned_items.as_mut().unwrap(); + if let Some(idx) = caller_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); + caller_mentioned_items.remove(idx); + caller_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, so we already diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index ac3a44c803a..1f214bc42cb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -28,11 +28,10 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; -use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, - LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, - SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, + AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl, + MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, + Statement, StatementKind, TerminatorKind, START_BLOCK, }; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::util::Providers; @@ -339,12 +338,15 @@ fn mir_promoted( // Collect `required_consts` *before* promotion, so if there are any consts being promoted // we still add them to the list in the outer MIR body. - let mut required_consts = Vec::new(); - let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); - for (bb, bb_data) in traversal::reverse_postorder(&body) { - required_consts_visitor.visit_basic_block_data(bb, bb_data); + RequiredConstsVisitor::compute_required_consts(&mut body); + // If this has an associated by-move async closure body, that doesn't get run through these + // passes itself, it gets "tagged along" by the pass manager. `RequiredConstsVisitor` is not + // a regular pass so we have to also apply it manually to the other body. + if let Some(coroutine) = body.coroutine.as_mut() { + if let Some(by_move_body) = coroutine.by_move_body.as_mut() { + RequiredConstsVisitor::compute_required_consts(by_move_body); + } } - body.required_consts = required_consts; // What we need to run borrowck etc. let promote_pass = promote_consts::PromoteTemps::default(); @@ -561,9 +563,6 @@ 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. @@ -657,6 +656,19 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { return body; } + // Before doing anything, remember which items are being mentioned so that the set of items + // visited does not depend on the optimization level. + // We do not use `run_passes` for this as that might skip the pass if `injection_phase` is set. + mentioned_items::MentionedItems.run_pass(tcx, &mut body); + // If this has an associated by-move async closure body, that doesn't get run through these + // passes itself, it gets "tagged along" by the pass manager. Since we're not using the pass + // manager we have to do this by hand. + if let Some(coroutine) = body.coroutine.as_mut() { + if let Some(by_move_body) = coroutine.by_move_body.as_mut() { + mentioned_items::MentionedItems.run_pass(tcx, by_move_body); + } + } + // If `mir_drops_elaborated_and_const_checked` found that the current body has unsatisfiable // predicates, it will shrink the MIR to a single `unreachable` terminator. // More generally, if MIR is a lone `unreachable`, there is nothing to optimize. diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index e33bdd99421..32c8064ebca 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -23,10 +23,9 @@ impl<'tcx> MirPass<'tcx> for MentionedItems { } 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; + body.set_mentioned_items(mentioned_items); } } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index f8971387ea4..dc8e50ac8cd 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -702,6 +702,9 @@ struct Promoter<'a, 'tcx> { temps: &'a mut IndexVec<Local, TempState>, extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>, + /// Used to assemble the required_consts list while building the promoted. + required_consts: Vec<ConstOperand<'tcx>>, + /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. keep_original: bool, @@ -924,11 +927,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let span = self.promoted.span; self.assign(RETURN_PLACE, rvalue, span); - // Now that we did promotion, we know whether we'll want to add this to `required_consts`. + // Now that we did promotion, we know whether we'll want to add this to `required_consts` of + // the surrounding MIR body. if self.add_to_required { - self.source.required_consts.push(promoted_op); + self.source.required_consts.as_mut().unwrap().push(promoted_op); } + self.promoted.set_required_consts(self.required_consts); + self.promoted } } @@ -947,7 +953,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) { if constant.const_.is_required_const() { - self.promoted.required_consts.push(*constant); + self.required_consts.push(*constant); } // Skipping `super_constant` as the visitor is otherwise only looking for locals. @@ -1011,9 +1017,9 @@ fn promote_candidates<'tcx>( extra_statements: &mut extra_statements, keep_original: false, add_to_required: false, + required_consts: Vec::new(), }; - // `required_consts` of the promoted itself gets filled while building the MIR body. let mut promoted = promoter.promote_candidate(candidate, promotions.len()); promoted.source.promoted = Some(promotions.next_index()); promotions.push(promoted); diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 00bfb5e6600..50637e2ac03 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -1,14 +1,23 @@ use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ConstOperand, Location}; +use rustc_middle::mir::{traversal, Body, ConstOperand, Location}; pub struct RequiredConstsVisitor<'a, 'tcx> { required_consts: &'a mut Vec<ConstOperand<'tcx>>, } impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { - pub fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self { + fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self { RequiredConstsVisitor { required_consts } } + + pub fn compute_required_consts(body: &mut Body<'tcx>) { + let mut required_consts = Vec::new(); + let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts); + for (bb, bb_data) in traversal::reverse_postorder(&body) { + required_consts_visitor.visit_basic_block_data(bb, bb_data); + } + body.set_required_consts(required_consts); + } } impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index e2fafa3a1a3..f41f3ef656c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -305,7 +305,7 @@ fn new_body<'tcx>( arg_count: usize, span: Span, ) -> Body<'tcx> { - Body::new( + let mut body = Body::new( source, basic_blocks, IndexVec::from_elem_n( @@ -326,7 +326,10 @@ fn new_body<'tcx>( None, // FIXME(compiler-errors): is this correct? None, - ) + ); + // Shims do not directly mention any consts. + body.set_required_consts(Vec::new()); + body } pub struct DropShimElaborator<'a, 'tcx> { @@ -969,13 +972,16 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { }; let source = MirSource::item(ctor_id); - let body = new_body( + let mut body = new_body( source, IndexVec::from_elem_n(start_block, 1), local_decls, sig.inputs().len(), span, ); + // A constructor doesn't mention any other items (and we don't run the usual optimization passes + // so this would otherwise not get filled). + body.set_mentioned_items(Vec::new()); crate::pass_manager::dump_mir_for_phase_change(tcx, &body); |
