Skip to content

Commit 32fe00a

Browse files
committed
Reuse CollectAndPatch for normal ConstProp.
1 parent 8a3a0dd commit 32fe00a

File tree

2 files changed

+72
-90
lines changed

2 files changed

+72
-90
lines changed

compiler/rustc_mir_transform/src/const_prop.rs

+27-53
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ use rustc_middle::mir::visit::{
1515
use rustc_middle::mir::*;
1616
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
1717
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
18-
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
18+
use rustc_span::{def_id::DefId, Span};
1919
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
2020
use rustc_target::spec::abi::Abi as CallAbi;
2121

22+
use crate::dataflow_const_prop::Patch;
2223
use crate::MirPass;
2324
use rustc_const_eval::interpret::{
2425
self, compile_time_machine, AllocId, ConstAllocation, ConstValue, FnArg, Frame, ImmTy,
@@ -120,6 +121,8 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
120121
optimization_finder.visit_basic_block_data(bb, data);
121122
}
122123

124+
optimization_finder.patch.visit_body_preserves_cfg(body);
125+
123126
trace!("ConstProp done for {:?}", def_id);
124127
}
125128
}
@@ -302,6 +305,7 @@ struct ConstPropagator<'mir, 'tcx> {
302305
tcx: TyCtxt<'tcx>,
303306
param_env: ParamEnv<'tcx>,
304307
local_decls: &'mir IndexSlice<Local, LocalDecl<'tcx>>,
308+
patch: Patch<'tcx>,
305309
}
306310

307311
impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
@@ -385,7 +389,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
385389
ecx.frame_mut().locals[local].make_live_uninit();
386390
}
387391

388-
ConstPropagator { ecx, tcx, param_env, local_decls: &dummy_body.local_decls }
392+
let patch = Patch::new(tcx);
393+
ConstPropagator { ecx, tcx, param_env, local_decls: &dummy_body.local_decls, patch }
389394
}
390395

391396
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
@@ -422,12 +427,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
422427
ecx.machine.written_only_inside_own_block_locals.remove(&local);
423428
}
424429

425-
fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
426-
if let Some(place) = operand.place() && let Some(op) = self.replace_with_const(place) {
427-
*operand = op;
428-
}
429-
}
430-
431430
fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<()> {
432431
// Perform any special handling for specific Rvalue types.
433432
// Generally, checks here fall into one of two categories:
@@ -543,16 +542,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
543542
}
544543
}
545544

546-
/// Creates a new `Operand::Constant` from a `Scalar` value
547-
fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> Operand<'tcx> {
548-
Operand::Constant(Box::new(Constant {
549-
span: DUMMY_SP,
550-
user_ty: None,
551-
literal: ConstantKind::from_scalar(self.tcx, scalar, ty),
552-
}))
553-
}
554-
555-
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Operand<'tcx>> {
545+
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<ConstantKind<'tcx>> {
556546
// This will return None if the above `const_prop` invocation only "wrote" a
557547
// type whose creation requires no write. E.g. a generator whose initial state
558548
// consists solely of uninitialized memory (so it doesn't capture any locals).
@@ -568,7 +558,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
568558
let Right(imm) = imm else { return None };
569559
match *imm {
570560
Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
571-
Some(self.operand_from_scalar(scalar, value.layout.ty))
561+
Some(ConstantKind::from_scalar(self.tcx, scalar, value.layout.ty))
572562
}
573563
Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
574564
let alloc = self
@@ -578,15 +568,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
578568
})
579569
.ok()?;
580570

581-
let literal = ConstantKind::Val(
571+
Some(ConstantKind::Val(
582572
ConstValue::ByRef { alloc, offset: Size::ZERO },
583573
value.layout.ty,
584-
);
585-
Some(Operand::Constant(Box::new(Constant {
586-
span: DUMMY_SP,
587-
user_ty: None,
588-
literal,
589-
})))
574+
))
590575
}
591576
// Scalars or scalar pairs that contain undef values are assumed to not have
592577
// successfully evaluated and are thus not propagated.
@@ -728,40 +713,29 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
728713
}
729714
}
730715

731-
impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
732-
fn tcx(&self) -> TyCtxt<'tcx> {
733-
self.tcx
734-
}
735-
736-
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
716+
impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
717+
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
737718
self.super_operand(operand, location);
738-
self.propagate_operand(operand)
719+
if let Some(place) = operand.place() && let Some(value) = self.replace_with_const(place) {
720+
self.patch.before_effect.insert((location, place), value);
721+
}
739722
}
740723

741-
fn process_projection_elem(
724+
fn visit_projection_elem(
742725
&mut self,
726+
_: PlaceRef<'tcx>,
743727
elem: PlaceElem<'tcx>,
744-
_: Location,
745-
) -> Option<PlaceElem<'tcx>> {
728+
_: PlaceContext,
729+
location: Location,
730+
) {
746731
if let PlaceElem::Index(local) = elem
747-
&& let Some(value) = self.get_const(local.into())
748-
&& let Some(imm) = value.as_mplace_or_imm().right()
749-
&& let Immediate::Scalar(scalar) = *imm
750-
&& let Ok(offset) = scalar.to_target_usize(&self.tcx)
751-
&& let Some(min_length) = offset.checked_add(1)
732+
&& let Some(value) = self.replace_with_const(local.into())
752733
{
753-
Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
754-
} else {
755-
None
734+
self.patch.before_effect.insert((location, local.into()), value);
756735
}
757736
}
758737

759-
fn visit_assign(
760-
&mut self,
761-
place: &mut Place<'tcx>,
762-
rvalue: &mut Rvalue<'tcx>,
763-
location: Location,
764-
) {
738+
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
765739
self.super_assign(place, rvalue, location);
766740

767741
let Some(()) = self.check_rvalue(rvalue) else { return };
@@ -778,7 +752,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
778752
{
779753
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
780754
} else if let Some(operand) = self.replace_with_const(*place) {
781-
*rvalue = Rvalue::Use(operand);
755+
self.patch.assignments.insert(location, operand);
782756
}
783757
} else {
784758
// Const prop failed, so erase the destination, ensuring that whatever happens
@@ -802,7 +776,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
802776
}
803777
}
804778

805-
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
779+
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
806780
trace!("visit_statement: {:?}", statement);
807781

808782
// We want to evaluate operands before any change to the assigned-to value,
@@ -846,7 +820,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
846820
}
847821
}
848822

849-
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
823+
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
850824
self.super_basic_block_data(block, data);
851825

852826
// We remove all Locals which are restricted in propagation to their containing blocks and

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

+45-37
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_hir::def::DefKind;
99
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, ConstValue, InterpResult, Scalar};
10-
use rustc_middle::mir::visit::{MutVisitor, NonMutatingUseContext, PlaceContext, Visitor};
10+
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
1111
use rustc_middle::mir::*;
1212
use rustc_middle::ty::layout::TyAndLayout;
1313
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -60,13 +60,10 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
6060
.in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
6161

6262
// Collect results and patch the body afterwards.
63-
let mut visitor = CollectAndPatch::new(tcx, &body.local_decls);
63+
let mut visitor = Collector::new(tcx, &body.local_decls);
6464
debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
65-
debug_span!("patch").in_scope(|| {
66-
for (block, bbdata) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
67-
visitor.visit_basic_block_data(block, bbdata);
68-
}
69-
})
65+
let mut patch = visitor.patch;
66+
debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
7067
}
7168
}
7269

@@ -517,27 +514,36 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
517514
}
518515
}
519516

520-
struct CollectAndPatch<'tcx, 'locals> {
517+
pub(crate) struct Patch<'tcx> {
521518
tcx: TyCtxt<'tcx>,
522-
local_decls: &'locals LocalDecls<'tcx>,
523519

524520
/// For a given MIR location, this stores the values of the operands used by that location. In
525521
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
526522
/// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
527-
before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>,
523+
pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>,
528524

529525
/// Stores the assigned values for assignments where the Rvalue is constant.
530-
assignments: FxHashMap<Location, ConstantKind<'tcx>>,
526+
pub(crate) assignments: FxHashMap<Location, ConstantKind<'tcx>>,
531527
}
532528

533-
impl<'tcx, 'locals> CollectAndPatch<'tcx, 'locals> {
534-
fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self {
535-
Self {
536-
tcx,
537-
local_decls,
538-
before_effect: FxHashMap::default(),
539-
assignments: FxHashMap::default(),
540-
}
529+
impl<'tcx> Patch<'tcx> {
530+
pub(crate) fn new(tcx: TyCtxt<'tcx>) -> Self {
531+
Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
532+
}
533+
534+
fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> {
535+
Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal }))
536+
}
537+
}
538+
539+
struct Collector<'tcx, 'locals> {
540+
patch: Patch<'tcx>,
541+
local_decls: &'locals LocalDecls<'tcx>,
542+
}
543+
544+
impl<'tcx, 'locals> Collector<'tcx, 'locals> {
545+
pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self {
546+
Self { patch: Patch::new(tcx), local_decls }
541547
}
542548

543549
fn try_make_constant(
@@ -549,18 +555,14 @@ impl<'tcx, 'locals> CollectAndPatch<'tcx, 'locals> {
549555
let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
550556
return None;
551557
};
552-
let ty = place.ty(self.local_decls, self.tcx).ty;
558+
let ty = place.ty(self.local_decls, self.patch.tcx).ty;
553559
Some(ConstantKind::Val(ConstValue::Scalar(value.into()), ty))
554560
}
555-
556-
fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> {
557-
Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal }))
558-
}
559561
}
560562

561563
impl<'mir, 'tcx>
562564
ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
563-
for CollectAndPatch<'tcx, '_>
565+
for Collector<'tcx, '_>
564566
{
565567
type FlowState = State<FlatSet<Scalar>>;
566568

@@ -593,7 +595,7 @@ impl<'mir, 'tcx>
593595
}
594596
StatementKind::Assign(box (place, _)) => {
595597
if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) {
596-
self.assignments.insert(location, value);
598+
self.patch.assignments.insert(location, value);
597599
}
598600
}
599601
_ => (),
@@ -612,7 +614,7 @@ impl<'mir, 'tcx>
612614
}
613615
}
614616

615-
impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
617+
impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
616618
fn tcx(&self) -> TyCtxt<'tcx> {
617619
self.tcx
618620
}
@@ -662,29 +664,35 @@ impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx, '_> {
662664

663665
struct OperandCollector<'tcx, 'map, 'locals, 'a> {
664666
state: &'a State<FlatSet<Scalar>>,
665-
visitor: &'a mut CollectAndPatch<'tcx, 'locals>,
667+
visitor: &'a mut Collector<'tcx, 'locals>,
666668
map: &'map Map,
667669
}
668670

669671
impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
672+
fn visit_projection_elem(
673+
&mut self,
674+
_: PlaceRef<'tcx>,
675+
elem: PlaceElem<'tcx>,
676+
_: PlaceContext,
677+
location: Location,
678+
) {
679+
if let PlaceElem::Index(local) = elem
680+
&& let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map)
681+
{
682+
self.visitor.patch.before_effect.insert((location, local.into()), value);
683+
}
684+
}
685+
670686
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
671687
if let Some(place) = operand.place() {
672688
if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) {
673-
self.visitor.before_effect.insert((location, place), value);
689+
self.visitor.patch.before_effect.insert((location, place), value);
674690
} else if !place.projection.is_empty() {
675691
// Try to propagate into `Index` projections.
676692
self.super_operand(operand, location)
677693
}
678694
}
679695
}
680-
681-
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, location: Location) {
682-
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy | NonMutatingUseContext::Move) = ctxt
683-
&& let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map)
684-
{
685-
self.visitor.before_effect.insert((location, local.into()), value);
686-
}
687-
}
688696
}
689697

690698
struct DummyMachine;

0 commit comments

Comments
 (0)