Rollup merge of #99178 - Dajamante:clean_up, r=oli-obk
Lighten up const_prop_lint, reusing const_prop r? `@oli-obk`
This commit is contained in:
commit
74be487ca0
2 changed files with 23 additions and 344 deletions
|
@ -155,18 +155,18 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConstPropMachine<'mir, 'tcx> {
|
pub struct ConstPropMachine<'mir, 'tcx> {
|
||||||
/// The virtual call stack.
|
/// The virtual call stack.
|
||||||
stack: Vec<Frame<'mir, 'tcx>>,
|
stack: Vec<Frame<'mir, 'tcx>>,
|
||||||
/// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
|
/// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
|
||||||
written_only_inside_own_block_locals: FxHashSet<Local>,
|
pub written_only_inside_own_block_locals: FxHashSet<Local>,
|
||||||
/// Locals that need to be cleared after every block terminates.
|
/// Locals that need to be cleared after every block terminates.
|
||||||
only_propagate_inside_block_locals: BitSet<Local>,
|
pub only_propagate_inside_block_locals: BitSet<Local>,
|
||||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
pub can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstPropMachine<'_, '_> {
|
impl ConstPropMachine<'_, '_> {
|
||||||
fn new(
|
pub fn new(
|
||||||
only_propagate_inside_block_locals: BitSet<Local>,
|
only_propagate_inside_block_locals: BitSet<Local>,
|
||||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -816,7 +816,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
|
|
||||||
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
|
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
enum ConstPropMode {
|
pub enum ConstPropMode {
|
||||||
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
|
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
|
||||||
FullConstProp,
|
FullConstProp,
|
||||||
/// The `Local` can only be propagated into and from its own block.
|
/// The `Local` can only be propagated into and from its own block.
|
||||||
|
@ -828,7 +828,7 @@ enum ConstPropMode {
|
||||||
NoPropagation,
|
NoPropagation,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CanConstProp {
|
pub struct CanConstProp {
|
||||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
can_const_prop: IndexVec<Local, ConstPropMode>,
|
||||||
// False at the beginning. Once set, no more assignments are allowed to that local.
|
// False at the beginning. Once set, no more assignments are allowed to that local.
|
||||||
found_assignment: BitSet<Local>,
|
found_assignment: BitSet<Local>,
|
||||||
|
@ -838,7 +838,7 @@ struct CanConstProp {
|
||||||
|
|
||||||
impl CanConstProp {
|
impl CanConstProp {
|
||||||
/// Returns true if `local` can be propagated
|
/// Returns true if `local` can be propagated
|
||||||
fn check<'tcx>(
|
pub fn check<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
body: &Body<'tcx>,
|
body: &Body<'tcx>,
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
//! Propagates constants for early reporting of statically known
|
//! Propagates constants for early reporting of statically known
|
||||||
//! assertion failures
|
//! assertion failures
|
||||||
|
|
||||||
use std::cell::Cell;
|
use crate::const_prop::CanConstProp;
|
||||||
|
use crate::const_prop::ConstPropMachine;
|
||||||
use rustc_ast::Mutability;
|
use crate::const_prop::ConstPropMode;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use crate::MirLint;
|
||||||
|
use rustc_const_eval::const_eval::ConstEvalErr;
|
||||||
|
use rustc_const_eval::interpret::{
|
||||||
|
self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar,
|
||||||
|
ScalarMaybeUninit, StackPopCleanup,
|
||||||
|
};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind,
|
AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, Location, Operand, Place,
|
||||||
Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
|
Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator,
|
||||||
StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
|
TerminatorKind, UnOp, RETURN_PLACE,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||||
|
@ -22,42 +27,15 @@ use rustc_middle::ty::{
|
||||||
TypeVisitable,
|
TypeVisitable,
|
||||||
};
|
};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::{def_id::DefId, Span};
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
||||||
use rustc_target::spec::abi::Abi as CallAbi;
|
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
use std::cell::Cell;
|
||||||
use crate::MirLint;
|
|
||||||
use rustc_const_eval::const_eval::ConstEvalErr;
|
|
||||||
use rustc_const_eval::interpret::{
|
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
|
|
||||||
LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
|
|
||||||
StackPopCleanup, StackPopUnwind,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||||
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
|
/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
|
||||||
/// Severely regress performance.
|
/// Severely regress performance.
|
||||||
const MAX_ALLOC_LIMIT: u64 = 1024;
|
const MAX_ALLOC_LIMIT: u64 = 1024;
|
||||||
|
|
||||||
/// Macro for machine-specific `InterpError` without allocation.
|
|
||||||
/// (These will never be shown to the user, but they help diagnose ICEs.)
|
|
||||||
macro_rules! throw_machine_stop_str {
|
|
||||||
($($tt:tt)*) => {{
|
|
||||||
// We make a new local type for it. The type itself does not carry any information,
|
|
||||||
// but its vtable (for the `MachineStopType` trait) does.
|
|
||||||
struct Zst;
|
|
||||||
// Printing this type shows the desired string.
|
|
||||||
impl std::fmt::Display for Zst {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, $($tt)*)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl rustc_middle::mir::interpret::MachineStopType for Zst {}
|
|
||||||
throw_machine_stop!(Zst)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ConstProp;
|
pub struct ConstProp;
|
||||||
|
|
||||||
impl<'tcx> MirLint<'tcx> for ConstProp {
|
impl<'tcx> MirLint<'tcx> for ConstProp {
|
||||||
|
@ -151,172 +129,6 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConstPropMachine<'mir, 'tcx> {
|
|
||||||
/// The virtual call stack.
|
|
||||||
stack: Vec<Frame<'mir, 'tcx>>,
|
|
||||||
/// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
|
|
||||||
written_only_inside_own_block_locals: FxHashSet<Local>,
|
|
||||||
/// Locals that need to be cleared after every block terminates.
|
|
||||||
only_propagate_inside_block_locals: BitSet<Local>,
|
|
||||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ConstPropMachine<'_, '_> {
|
|
||||||
fn new(
|
|
||||||
only_propagate_inside_block_locals: BitSet<Local>,
|
|
||||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
stack: Vec::new(),
|
|
||||||
written_only_inside_own_block_locals: Default::default(),
|
|
||||||
only_propagate_inside_block_locals,
|
|
||||||
can_const_prop,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
|
|
||||||
compile_time_machine!(<'mir, 'tcx>);
|
|
||||||
const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`)
|
|
||||||
|
|
||||||
type MemoryKind = !;
|
|
||||||
|
|
||||||
fn load_mir(
|
|
||||||
_ecx: &InterpCx<'mir, 'tcx, Self>,
|
|
||||||
_instance: ty::InstanceDef<'tcx>,
|
|
||||||
) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
|
|
||||||
throw_machine_stop_str!("calling functions isn't supported in ConstProp")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_mir_or_eval_fn(
|
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
_instance: ty::Instance<'tcx>,
|
|
||||||
_abi: CallAbi,
|
|
||||||
_args: &[OpTy<'tcx>],
|
|
||||||
_destination: &PlaceTy<'tcx>,
|
|
||||||
_target: Option<BasicBlock>,
|
|
||||||
_unwind: StackPopUnwind,
|
|
||||||
) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call_intrinsic(
|
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
_instance: ty::Instance<'tcx>,
|
|
||||||
_args: &[OpTy<'tcx>],
|
|
||||||
_destination: &PlaceTy<'tcx>,
|
|
||||||
_target: Option<BasicBlock>,
|
|
||||||
_unwind: StackPopUnwind,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_panic(
|
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
|
||||||
_unwind: Option<rustc_middle::mir::BasicBlock>,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
bug!("panics terminators are not evaluated in ConstProp")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn binary_ptr_op(
|
|
||||||
_ecx: &InterpCx<'mir, 'tcx, Self>,
|
|
||||||
_bin_op: BinOp,
|
|
||||||
_left: &ImmTy<'tcx>,
|
|
||||||
_right: &ImmTy<'tcx>,
|
|
||||||
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
|
|
||||||
// We can't do this because aliasing of memory can differ between const eval and llvm
|
|
||||||
throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn access_local<'a>(
|
|
||||||
frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
|
|
||||||
local: Local,
|
|
||||||
) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
|
|
||||||
let l = &frame.locals[local];
|
|
||||||
|
|
||||||
if matches!(
|
|
||||||
l.value,
|
|
||||||
LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
|
|
||||||
) {
|
|
||||||
// For us "uninit" means "we don't know its value, might be initiailized or not".
|
|
||||||
// So stop here.
|
|
||||||
throw_machine_stop_str!("tried to access a local with unknown value")
|
|
||||||
}
|
|
||||||
|
|
||||||
l.access()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn access_local_mut<'a>(
|
|
||||||
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
frame: usize,
|
|
||||||
local: Local,
|
|
||||||
) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> {
|
|
||||||
if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
|
|
||||||
throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
|
|
||||||
}
|
|
||||||
if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
|
|
||||||
trace!(
|
|
||||||
"mutating local {:?} which is restricted to its block. \
|
|
||||||
Will remove it from const-prop after block is finished.",
|
|
||||||
local
|
|
||||||
);
|
|
||||||
ecx.machine.written_only_inside_own_block_locals.insert(local);
|
|
||||||
}
|
|
||||||
ecx.machine.stack[frame].locals[local].access_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before_access_global(
|
|
||||||
_tcx: TyCtxt<'tcx>,
|
|
||||||
_machine: &Self,
|
|
||||||
_alloc_id: AllocId,
|
|
||||||
alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>,
|
|
||||||
_static_def_id: Option<DefId>,
|
|
||||||
is_write: bool,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
if is_write {
|
|
||||||
throw_machine_stop_str!("can't write to global");
|
|
||||||
}
|
|
||||||
// If the static allocation is mutable, then we can't const prop it as its content
|
|
||||||
// might be different at runtime.
|
|
||||||
if alloc.inner().mutability == Mutability::Mut {
|
|
||||||
throw_machine_stop_str!("can't access mutable globals in ConstProp");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn expose_ptr(
|
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
_ptr: Pointer<AllocId>,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn init_frame_extra(
|
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
frame: Frame<'mir, 'tcx>,
|
|
||||||
) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
|
|
||||||
Ok(frame)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn stack<'a>(
|
|
||||||
ecx: &'a InterpCx<'mir, 'tcx, Self>,
|
|
||||||
) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
|
|
||||||
&ecx.machine.stack
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn stack_mut<'a>(
|
|
||||||
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
|
|
||||||
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
|
|
||||||
&mut ecx.machine.stack
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds optimization opportunities on the MIR.
|
/// Finds optimization opportunities on the MIR.
|
||||||
struct ConstPropagator<'mir, 'tcx> {
|
struct ConstPropagator<'mir, 'tcx> {
|
||||||
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
|
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
|
||||||
|
@ -711,139 +523,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The mode that `ConstProp` is allowed to run in for a given `Local`.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
||||||
enum ConstPropMode {
|
|
||||||
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
|
|
||||||
FullConstProp,
|
|
||||||
/// The `Local` can only be propagated into and from its own block.
|
|
||||||
OnlyInsideOwnBlock,
|
|
||||||
/// The `Local` can be propagated into but reads cannot be propagated.
|
|
||||||
OnlyPropagateInto,
|
|
||||||
/// The `Local` cannot be part of propagation at all. Any statement
|
|
||||||
/// referencing it either for reading or writing will not get propagated.
|
|
||||||
NoPropagation,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CanConstProp {
|
|
||||||
can_const_prop: IndexVec<Local, ConstPropMode>,
|
|
||||||
// False at the beginning. Once set, no more assignments are allowed to that local.
|
|
||||||
found_assignment: BitSet<Local>,
|
|
||||||
// Cache of locals' information
|
|
||||||
local_kinds: IndexVec<Local, LocalKind>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CanConstProp {
|
|
||||||
/// Returns true if `local` can be propagated
|
|
||||||
fn check<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
param_env: ParamEnv<'tcx>,
|
|
||||||
body: &Body<'tcx>,
|
|
||||||
) -> IndexVec<Local, ConstPropMode> {
|
|
||||||
let mut cpv = CanConstProp {
|
|
||||||
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
|
|
||||||
found_assignment: BitSet::new_empty(body.local_decls.len()),
|
|
||||||
local_kinds: IndexVec::from_fn_n(
|
|
||||||
|local| body.local_kind(local),
|
|
||||||
body.local_decls.len(),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
|
|
||||||
let ty = body.local_decls[local].ty;
|
|
||||||
match tcx.layout_of(param_env.and(ty)) {
|
|
||||||
Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
|
|
||||||
// Either the layout fails to compute, then we can't use this local anyway
|
|
||||||
// or the local is too large, then we don't want to.
|
|
||||||
_ => {
|
|
||||||
*val = ConstPropMode::NoPropagation;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Cannot use args at all
|
|
||||||
// Cannot use locals because if x < y { y - x } else { x - y } would
|
|
||||||
// lint for x != y
|
|
||||||
// FIXME(oli-obk): lint variables until they are used in a condition
|
|
||||||
// FIXME(oli-obk): lint if return value is constant
|
|
||||||
if cpv.local_kinds[local] == LocalKind::Arg {
|
|
||||||
*val = ConstPropMode::OnlyPropagateInto;
|
|
||||||
trace!(
|
|
||||||
"local {:?} can't be const propagated because it's a function argument",
|
|
||||||
local
|
|
||||||
);
|
|
||||||
} else if cpv.local_kinds[local] == LocalKind::Var {
|
|
||||||
*val = ConstPropMode::OnlyInsideOwnBlock;
|
|
||||||
trace!(
|
|
||||||
"local {:?} will only be propagated inside its block, because it's a user variable",
|
|
||||||
local
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cpv.visit_body(&body);
|
|
||||||
cpv.can_const_prop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Visitor<'_> for CanConstProp {
|
|
||||||
fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
|
|
||||||
use rustc_middle::mir::visit::PlaceContext::*;
|
|
||||||
match context {
|
|
||||||
// Projections are fine, because `&mut foo.x` will be caught by
|
|
||||||
// `MutatingUseContext::Borrow` elsewhere.
|
|
||||||
MutatingUse(MutatingUseContext::Projection)
|
|
||||||
// These are just stores, where the storing is not propagatable, but there may be later
|
|
||||||
// mutations of the same local via `Store`
|
|
||||||
| MutatingUse(MutatingUseContext::Call)
|
|
||||||
| MutatingUse(MutatingUseContext::AsmOutput)
|
|
||||||
| MutatingUse(MutatingUseContext::Deinit)
|
|
||||||
// Actual store that can possibly even propagate a value
|
|
||||||
| MutatingUse(MutatingUseContext::SetDiscriminant)
|
|
||||||
| MutatingUse(MutatingUseContext::Store) => {
|
|
||||||
if !self.found_assignment.insert(local) {
|
|
||||||
match &mut self.can_const_prop[local] {
|
|
||||||
// If the local can only get propagated in its own block, then we don't have
|
|
||||||
// to worry about multiple assignments, as we'll nuke the const state at the
|
|
||||||
// end of the block anyway, and inside the block we overwrite previous
|
|
||||||
// states as applicable.
|
|
||||||
ConstPropMode::OnlyInsideOwnBlock => {}
|
|
||||||
ConstPropMode::NoPropagation => {}
|
|
||||||
ConstPropMode::OnlyPropagateInto => {}
|
|
||||||
other @ ConstPropMode::FullConstProp => {
|
|
||||||
trace!(
|
|
||||||
"local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
|
|
||||||
local, other,
|
|
||||||
);
|
|
||||||
*other = ConstPropMode::OnlyInsideOwnBlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reading constants is allowed an arbitrary number of times
|
|
||||||
NonMutatingUse(NonMutatingUseContext::Copy)
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::Move)
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::Inspect)
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::Projection)
|
|
||||||
| NonUse(_) => {}
|
|
||||||
|
|
||||||
// These could be propagated with a smarter analysis or just some careful thinking about
|
|
||||||
// whether they'd be fine right now.
|
|
||||||
MutatingUse(MutatingUseContext::Yield)
|
|
||||||
| MutatingUse(MutatingUseContext::Drop)
|
|
||||||
| MutatingUse(MutatingUseContext::Retag)
|
|
||||||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
|
||||||
// mutation.
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
|
|
||||||
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
|
||||||
| MutatingUse(MutatingUseContext::Borrow)
|
|
||||||
| MutatingUse(MutatingUseContext::AddressOf) => {
|
|
||||||
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
|
|
||||||
self.can_const_prop[local] = ConstPropMode::NoPropagation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||||
fn visit_body(&mut self, body: &Body<'tcx>) {
|
fn visit_body(&mut self, body: &Body<'tcx>) {
|
||||||
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
for (bb, data) in body.basic_blocks().iter_enumerated() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue