Skip to content

Commit 50e316b

Browse files
committed
Remove const_prop.rs
and move its content to const_prop_lint.rs and dataflow_const_prop.rs where it is used
1 parent 23a3d77 commit 50e316b

File tree

4 files changed

+153
-168
lines changed

4 files changed

+153
-168
lines changed

compiler/rustc_mir_transform/src/const_prop.rs

-161
This file was deleted.

compiler/rustc_mir_transform/src/const_prop_lint.rs

+127-5
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@ use rustc_const_eval::interpret::{
99
use rustc_data_structures::fx::FxHashSet;
1010
use rustc_hir::def::DefKind;
1111
use rustc_hir::HirId;
12-
use rustc_index::bit_set::BitSet;
13-
use rustc_index::{Idx, IndexVec};
14-
use rustc_middle::mir::visit::Visitor;
12+
use rustc_index::{bit_set::BitSet, Idx, IndexVec};
13+
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
1514
use rustc_middle::mir::*;
1615
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
1716
use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
1817
use rustc_span::Span;
1918
use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx};
2019

21-
use crate::const_prop::CanConstProp;
22-
use crate::const_prop::ConstPropMode;
2320
use crate::dataflow_const_prop::DummyMachine;
2421
use crate::errors::{AssertLint, AssertLintKind};
2522
use crate::MirLint;
@@ -849,3 +846,128 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
849846
}
850847
}
851848
}
849+
850+
/// The maximum number of bytes that we'll allocate space for a local or the return value.
851+
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
852+
/// Severely regress performance.
853+
const MAX_ALLOC_LIMIT: u64 = 1024;
854+
855+
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
856+
#[derive(Clone, Copy, Debug, PartialEq)]
857+
pub enum ConstPropMode {
858+
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
859+
FullConstProp,
860+
/// The `Local` can only be propagated into and from its own block.
861+
OnlyInsideOwnBlock,
862+
/// The `Local` cannot be part of propagation at all. Any statement
863+
/// referencing it either for reading or writing will not get propagated.
864+
NoPropagation,
865+
}
866+
867+
pub struct CanConstProp {
868+
can_const_prop: IndexVec<Local, ConstPropMode>,
869+
// False at the beginning. Once set, no more assignments are allowed to that local.
870+
found_assignment: BitSet<Local>,
871+
}
872+
873+
impl CanConstProp {
874+
/// Returns true if `local` can be propagated
875+
pub fn check<'tcx>(
876+
tcx: TyCtxt<'tcx>,
877+
param_env: ParamEnv<'tcx>,
878+
body: &Body<'tcx>,
879+
) -> IndexVec<Local, ConstPropMode> {
880+
let mut cpv = CanConstProp {
881+
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
882+
found_assignment: BitSet::new_empty(body.local_decls.len()),
883+
};
884+
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
885+
let ty = body.local_decls[local].ty;
886+
match tcx.layout_of(param_env.and(ty)) {
887+
Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
888+
// Either the layout fails to compute, then we can't use this local anyway
889+
// or the local is too large, then we don't want to.
890+
_ => {
891+
*val = ConstPropMode::NoPropagation;
892+
continue;
893+
}
894+
}
895+
}
896+
// Consider that arguments are assigned on entry.
897+
for arg in body.args_iter() {
898+
cpv.found_assignment.insert(arg);
899+
}
900+
cpv.visit_body(body);
901+
cpv.can_const_prop
902+
}
903+
}
904+
905+
impl<'tcx> Visitor<'tcx> for CanConstProp {
906+
fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
907+
use rustc_middle::mir::visit::PlaceContext::*;
908+
909+
// Dereferencing just read the addess of `place.local`.
910+
if place.projection.first() == Some(&PlaceElem::Deref) {
911+
context = NonMutatingUse(NonMutatingUseContext::Copy);
912+
}
913+
914+
self.visit_local(place.local, context, loc);
915+
self.visit_projection(place.as_ref(), context, loc);
916+
}
917+
918+
fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
919+
use rustc_middle::mir::visit::PlaceContext::*;
920+
match context {
921+
// These are just stores, where the storing is not propagatable, but there may be later
922+
// mutations of the same local via `Store`
923+
| MutatingUse(MutatingUseContext::Call)
924+
| MutatingUse(MutatingUseContext::AsmOutput)
925+
| MutatingUse(MutatingUseContext::Deinit)
926+
// Actual store that can possibly even propagate a value
927+
| MutatingUse(MutatingUseContext::Store)
928+
| MutatingUse(MutatingUseContext::SetDiscriminant) => {
929+
if !self.found_assignment.insert(local) {
930+
match &mut self.can_const_prop[local] {
931+
// If the local can only get propagated in its own block, then we don't have
932+
// to worry about multiple assignments, as we'll nuke the const state at the
933+
// end of the block anyway, and inside the block we overwrite previous
934+
// states as applicable.
935+
ConstPropMode::OnlyInsideOwnBlock => {}
936+
ConstPropMode::NoPropagation => {}
937+
other @ ConstPropMode::FullConstProp => {
938+
trace!(
939+
"local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
940+
local, other,
941+
);
942+
*other = ConstPropMode::OnlyInsideOwnBlock;
943+
}
944+
}
945+
}
946+
}
947+
// Reading constants is allowed an arbitrary number of times
948+
NonMutatingUse(NonMutatingUseContext::Copy)
949+
| NonMutatingUse(NonMutatingUseContext::Move)
950+
| NonMutatingUse(NonMutatingUseContext::Inspect)
951+
| NonMutatingUse(NonMutatingUseContext::PlaceMention)
952+
| NonUse(_) => {}
953+
954+
// These could be propagated with a smarter analysis or just some careful thinking about
955+
// whether they'd be fine right now.
956+
MutatingUse(MutatingUseContext::Yield)
957+
| MutatingUse(MutatingUseContext::Drop)
958+
| MutatingUse(MutatingUseContext::Retag)
959+
// These can't ever be propagated under any scheme, as we can't reason about indirect
960+
// mutation.
961+
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
962+
| NonMutatingUse(NonMutatingUseContext::FakeBorrow)
963+
| NonMutatingUse(NonMutatingUseContext::AddressOf)
964+
| MutatingUse(MutatingUseContext::Borrow)
965+
| MutatingUse(MutatingUseContext::AddressOf) => {
966+
trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
967+
self.can_const_prop[local] = ConstPropMode::NoPropagation;
968+
}
969+
MutatingUse(MutatingUseContext::Projection)
970+
| NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
971+
}
972+
}
973+
}

compiler/rustc_mir_transform/src/dataflow_const_prop.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,32 @@ use rustc_span::def_id::DefId;
2121
use rustc_span::DUMMY_SP;
2222
use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
2323

24-
use crate::const_prop::throw_machine_stop_str;
24+
/// Macro for machine-specific `InterpError` without allocation.
25+
/// (These will never be shown to the user, but they help diagnose ICEs.)
26+
pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
27+
// We make a new local type for it. The type itself does not carry any information,
28+
// but its vtable (for the `MachineStopType` trait) does.
29+
#[derive(Debug)]
30+
struct Zst;
31+
// Printing this type shows the desired string.
32+
impl std::fmt::Display for Zst {
33+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34+
write!(f, $($tt)*)
35+
}
36+
}
37+
38+
impl rustc_middle::mir::interpret::MachineStopType for Zst {
39+
fn diagnostic_message(&self) -> rustc_errors::DiagnosticMessage {
40+
self.to_string().into()
41+
}
42+
43+
fn add_args(
44+
self: Box<Self>,
45+
_: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
46+
) {}
47+
}
48+
throw_machine_stop!(Zst)
49+
}}
2550

2651
// These constants are somewhat random guesses and have not been optimized.
2752
// If `tcx.sess.mir_opt_level() >= 4`, we ignore the limits (this can become very expensive).

compiler/rustc_mir_transform/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ mod remove_place_mention;
5959
mod add_subtyping_projections;
6060
pub mod cleanup_post_borrowck;
6161
mod const_debuginfo;
62-
mod const_prop;
6362
mod const_prop_lint;
6463
mod copy_prop;
6564
mod coroutine;

0 commit comments

Comments
 (0)