Auto merge of #116012 - cjgillot:gvn-const, r=oli-obk
Implement constant propagation on top of MIR SSA analysis
This implements the idea I proposed in https://github.com/rust-lang/rust/pull/110719#issuecomment-1718324700
Based on https://github.com/rust-lang/rust/pull/109597
The value numbering "GVN" pass formulates each rvalue that appears in MIR with an abstract form (the `Value` enum), and assigns an integer `VnIndex` to each. This abstract form can be used to deduplicate values, reusing an earlier local that holds the same value instead of recomputing. This part is proposed in #109597.
From this abstract representation, we can perform more involved simplifications, for example in https://github.com/rust-lang/rust/pull/111344.
With the abstract representation `Value`, we can also attempt to evaluate each to a constant using the interpreter. This builds a `VnIndex -> OpTy` map. From this map, we can opportunistically replace an operand or a rvalue with a constant if their value has an associated `OpTy`.
The most relevant commit is [Evaluated computed values to constants.](2767c4912e
)"
r? `@oli-obk`
This commit is contained in:
commit
8d76d07666
209 changed files with 1094 additions and 1587 deletions
|
@ -1,6 +1,7 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use rustc_data_structures::sso::SsoHashMap;
|
use rustc_data_structures::sso::SsoHashMap;
|
||||||
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
|
@ -215,7 +216,9 @@ where
|
||||||
let old_ambient_variance = self.ambient_variance;
|
let old_ambient_variance = self.ambient_variance;
|
||||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||||
debug!(?self.ambient_variance, "new ambient variance");
|
debug!(?self.ambient_variance, "new ambient variance");
|
||||||
let r = self.relate(a, b)?;
|
// Recursive calls to `relate` can overflow the stack. For example a deeper version of
|
||||||
|
// `ui/associated-consts/issue-93775.rs`.
|
||||||
|
let r = ensure_sufficient_stack(|| self.relate(a, b))?;
|
||||||
self.ambient_variance = old_ambient_variance;
|
self.ambient_variance = old_ambient_variance;
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,22 @@
|
||||||
//! Propagates constants for early reporting of statically known
|
//! Propagates constants for early reporting of statically known
|
||||||
//! assertion failures
|
//! assertion failures
|
||||||
|
|
||||||
use either::Right;
|
use rustc_const_eval::interpret::{
|
||||||
use rustc_const_eval::ReportErrorExt;
|
self, compile_time_machine, AllocId, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
InterpResult, OpTy, PlaceTy, Pointer,
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use rustc_index::bit_set::BitSet;
|
|
||||||
use rustc_index::{IndexSlice, IndexVec};
|
|
||||||
use rustc_middle::mir::visit::{
|
|
||||||
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
|
|
||||||
};
|
};
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_index::bit_set::BitSet;
|
||||||
|
use rustc_index::IndexVec;
|
||||||
|
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::query::TyCtxtAt;
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
|
use rustc_middle::ty::layout::TyAndLayout;
|
||||||
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
|
||||||
use rustc_span::{def_id::DefId, Span};
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
|
use rustc_target::abi::Size;
|
||||||
use rustc_target::spec::abi::Abi as CallAbi;
|
use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
|
||||||
use crate::dataflow_const_prop::Patch;
|
|
||||||
use rustc_const_eval::interpret::{
|
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, FnArg, Frame, ImmTy, Immediate, InterpCx,
|
|
||||||
InterpResult, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, StackPopCleanup,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -56,62 +49,7 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
|
||||||
throw_machine_stop!(Zst)
|
throw_machine_stop!(Zst)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
pub struct ConstProp;
|
pub(crate) struct ConstPropMachine<'mir, 'tcx> {
|
||||||
|
|
||||||
impl<'tcx> MirPass<'tcx> for ConstProp {
|
|
||||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
|
||||||
sess.mir_opt_level() >= 2
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(skip(self, tcx), level = "debug")]
|
|
||||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|
||||||
// will be evaluated by miri and produce its errors there
|
|
||||||
if body.source.promoted.is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let def_id = body.source.def_id().expect_local();
|
|
||||||
let def_kind = tcx.def_kind(def_id);
|
|
||||||
let is_fn_like = def_kind.is_fn_like();
|
|
||||||
let is_assoc_const = def_kind == DefKind::AssocConst;
|
|
||||||
|
|
||||||
// Only run const prop on functions, methods, closures and associated constants
|
|
||||||
if !is_fn_like && !is_assoc_const {
|
|
||||||
// skip anon_const/statics/consts because they'll be evaluated by miri anyway
|
|
||||||
trace!("ConstProp skipped for {:?}", def_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles
|
|
||||||
// computing their layout.
|
|
||||||
if tcx.is_coroutine(def_id.to_def_id()) {
|
|
||||||
trace!("ConstProp skipped for coroutine {:?}", def_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("ConstProp starting for {:?}", def_id);
|
|
||||||
|
|
||||||
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
|
|
||||||
// constants, instead of just checking for const-folding succeeding.
|
|
||||||
// That would require a uniform one-def no-mutation analysis
|
|
||||||
// and RPO (or recursing when needing the value of a local).
|
|
||||||
let mut optimization_finder = ConstPropagator::new(body, tcx);
|
|
||||||
|
|
||||||
// Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
|
|
||||||
// assigned before being read.
|
|
||||||
for &bb in body.basic_blocks.reverse_postorder() {
|
|
||||||
let data = &body.basic_blocks[bb];
|
|
||||||
optimization_finder.visit_basic_block_data(bb, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut patch = optimization_finder.patch;
|
|
||||||
patch.visit_body_preserves_cfg(body);
|
|
||||||
|
|
||||||
trace!("ConstProp done for {:?}", def_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ConstPropMachine<'mir, 'tcx> {
|
|
||||||
/// The virtual call stack.
|
/// The virtual call stack.
|
||||||
stack: Vec<Frame<'mir, 'tcx>>,
|
stack: Vec<Frame<'mir, 'tcx>>,
|
||||||
pub written_only_inside_own_block_locals: FxHashSet<Local>,
|
pub written_only_inside_own_block_locals: FxHashSet<Local>,
|
||||||
|
@ -267,297 +205,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds optimization opportunities on the MIR.
|
|
||||||
struct ConstPropagator<'mir, 'tcx> {
|
|
||||||
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
param_env: ParamEnv<'tcx>,
|
|
||||||
local_decls: &'mir IndexSlice<Local, LocalDecl<'tcx>>,
|
|
||||||
patch: Patch<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
|
|
||||||
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
|
|
||||||
err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasDataLayout for ConstPropagator<'_, '_> {
|
|
||||||
#[inline]
|
|
||||||
fn data_layout(&self) -> &TargetDataLayout {
|
|
||||||
&self.tcx.data_layout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> {
|
|
||||||
#[inline]
|
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
|
||||||
self.tcx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
|
|
||||||
#[inline]
|
|
||||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
|
||||||
self.param_env
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|
||||||
fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
|
|
||||||
let def_id = body.source.def_id();
|
|
||||||
let args = &GenericArgs::identity_for_item(tcx, def_id);
|
|
||||||
let param_env = tcx.param_env_reveal_all_normalized(def_id);
|
|
||||||
|
|
||||||
let can_const_prop = CanConstProp::check(tcx, param_env, body);
|
|
||||||
let mut ecx = InterpCx::new(
|
|
||||||
tcx,
|
|
||||||
tcx.def_span(def_id),
|
|
||||||
param_env,
|
|
||||||
ConstPropMachine::new(can_const_prop),
|
|
||||||
);
|
|
||||||
|
|
||||||
let ret_layout = ecx
|
|
||||||
.layout_of(body.bound_return_ty().instantiate(tcx, args))
|
|
||||||
.ok()
|
|
||||||
// Don't bother allocating memory for large values.
|
|
||||||
// I don't know how return types can seem to be unsized but this happens in the
|
|
||||||
// `type/type-unsatisfiable.rs` test.
|
|
||||||
.filter(|ret_layout| {
|
|
||||||
ret_layout.is_sized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
|
|
||||||
|
|
||||||
let ret = ecx
|
|
||||||
.allocate(ret_layout, MemoryKind::Stack)
|
|
||||||
.expect("couldn't perform small allocation")
|
|
||||||
.into();
|
|
||||||
|
|
||||||
ecx.push_stack_frame(
|
|
||||||
Instance::new(def_id, args),
|
|
||||||
body,
|
|
||||||
&ret,
|
|
||||||
StackPopCleanup::Root { cleanup: false },
|
|
||||||
)
|
|
||||||
.expect("failed to push initial stack frame");
|
|
||||||
|
|
||||||
for local in body.local_decls.indices() {
|
|
||||||
// Mark everything initially live.
|
|
||||||
// This is somewhat dicey since some of them might be unsized and it is incoherent to
|
|
||||||
// mark those as live... We rely on `local_to_place`/`local_to_op` in the interpreter
|
|
||||||
// stopping us before those unsized immediates can cause issues deeper in the
|
|
||||||
// interpreter.
|
|
||||||
ecx.frame_mut().locals[local].make_live_uninit();
|
|
||||||
}
|
|
||||||
|
|
||||||
let patch = Patch::new(tcx);
|
|
||||||
ConstPropagator { ecx, tcx, param_env, local_decls: &body.local_decls, patch }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
|
|
||||||
let op = match self.ecx.eval_place_to_op(place, None) {
|
|
||||||
Ok(op) => {
|
|
||||||
if op
|
|
||||||
.as_mplace_or_imm()
|
|
||||||
.right()
|
|
||||||
.is_some_and(|imm| matches!(*imm, Immediate::Uninit))
|
|
||||||
{
|
|
||||||
// Make sure nobody accidentally uses this value.
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
op
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
trace!("get_const failed: {:?}", e.into_kind().debug());
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try to read the local as an immediate so that if it is representable as a scalar, we can
|
|
||||||
// handle it as such, but otherwise, just return the value as is.
|
|
||||||
Some(match self.ecx.read_immediate_raw(&op) {
|
|
||||||
Ok(Right(imm)) => imm.into(),
|
|
||||||
_ => op,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove `local` from the pool of `Locals`. Allows writing to them,
|
|
||||||
/// but not reading from them anymore.
|
|
||||||
fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
|
|
||||||
ecx.frame_mut().locals[local].make_live_uninit();
|
|
||||||
ecx.machine.written_only_inside_own_block_locals.remove(&local);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<()> {
|
|
||||||
// Perform any special handling for specific Rvalue types.
|
|
||||||
// Generally, checks here fall into one of two categories:
|
|
||||||
// 1. Additional checking to provide useful lints to the user
|
|
||||||
// - In this case, we will do some validation and then fall through to the
|
|
||||||
// end of the function which evals the assignment.
|
|
||||||
// 2. Working around bugs in other parts of the compiler
|
|
||||||
// - In this case, we'll return `None` from this function to stop evaluation.
|
|
||||||
match rvalue {
|
|
||||||
// Do not try creating references (#67862)
|
|
||||||
Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
|
|
||||||
trace!("skipping AddressOf | Ref for {:?}", place);
|
|
||||||
|
|
||||||
// This may be creating mutable references or immutable references to cells.
|
|
||||||
// If that happens, the pointed to value could be mutated via that reference.
|
|
||||||
// Since we aren't tracking references, the const propagator loses track of what
|
|
||||||
// value the local has right now.
|
|
||||||
// Thus, all locals that have their reference taken
|
|
||||||
// must not take part in propagation.
|
|
||||||
Self::remove_const(&mut self.ecx, place.local);
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Rvalue::ThreadLocalRef(def_id) => {
|
|
||||||
trace!("skipping ThreadLocalRef({:?})", def_id);
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
// There's no other checking to do at this time.
|
|
||||||
Rvalue::Aggregate(..)
|
|
||||||
| Rvalue::Use(..)
|
|
||||||
| Rvalue::CopyForDeref(..)
|
|
||||||
| Rvalue::Repeat(..)
|
|
||||||
| Rvalue::Len(..)
|
|
||||||
| Rvalue::Cast(..)
|
|
||||||
| Rvalue::ShallowInitBox(..)
|
|
||||||
| Rvalue::Discriminant(..)
|
|
||||||
| Rvalue::NullaryOp(..)
|
|
||||||
| Rvalue::UnaryOp(..)
|
|
||||||
| Rvalue::BinaryOp(..)
|
|
||||||
| Rvalue::CheckedBinaryOp(..) => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME we need to revisit this for #67176
|
|
||||||
if rvalue.has_param() {
|
|
||||||
trace!("skipping, has param");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if !rvalue
|
|
||||||
.ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
|
|
||||||
.is_sized(*self.ecx.tcx, self.param_env)
|
|
||||||
{
|
|
||||||
// the interpreter doesn't support unsized locals (only unsized arguments),
|
|
||||||
// but rustc does (in a kinda broken way), so we have to skip them here
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to use algebraic identities to eliminate constant expressions
|
|
||||||
fn eval_rvalue_with_identities(
|
|
||||||
&mut self,
|
|
||||||
rvalue: &Rvalue<'tcx>,
|
|
||||||
place: Place<'tcx>,
|
|
||||||
) -> Option<()> {
|
|
||||||
match rvalue {
|
|
||||||
Rvalue::BinaryOp(op, box (left, right))
|
|
||||||
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
|
|
||||||
let l = self.ecx.eval_operand(left, None).and_then(|x| self.ecx.read_immediate(&x));
|
|
||||||
let r =
|
|
||||||
self.ecx.eval_operand(right, None).and_then(|x| self.ecx.read_immediate(&x));
|
|
||||||
|
|
||||||
let const_arg = match (l, r) {
|
|
||||||
(Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known
|
|
||||||
(Err(_), Err(_)) => return None, // neither side is known
|
|
||||||
(Ok(_), Ok(_)) => return self.ecx.eval_rvalue_into_place(rvalue, place).ok(), // both sides are known
|
|
||||||
};
|
|
||||||
|
|
||||||
if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
|
|
||||||
// We cannot handle Scalar Pair stuff.
|
|
||||||
// No point in calling `eval_rvalue_into_place`, since only one side is known
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let arg_value = const_arg.to_scalar().to_bits(const_arg.layout.size).ok()?;
|
|
||||||
let dest = self.ecx.eval_place(place).ok()?;
|
|
||||||
|
|
||||||
match op {
|
|
||||||
BinOp::BitAnd if arg_value == 0 => {
|
|
||||||
self.ecx.write_immediate(*const_arg, &dest).ok()
|
|
||||||
}
|
|
||||||
BinOp::BitOr
|
|
||||||
if arg_value == const_arg.layout.size.truncate(u128::MAX)
|
|
||||||
|| (const_arg.layout.ty.is_bool() && arg_value == 1) =>
|
|
||||||
{
|
|
||||||
self.ecx.write_immediate(*const_arg, &dest).ok()
|
|
||||||
}
|
|
||||||
BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
|
|
||||||
if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
|
|
||||||
let val = Immediate::ScalarPair(
|
|
||||||
const_arg.to_scalar(),
|
|
||||||
Scalar::from_bool(false),
|
|
||||||
);
|
|
||||||
self.ecx.write_immediate(val, &dest).ok()
|
|
||||||
} else {
|
|
||||||
self.ecx.write_immediate(*const_arg, &dest).ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.ecx.eval_rvalue_into_place(rvalue, place).ok(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Const<'tcx>> {
|
|
||||||
// This will return None if the above `const_prop` invocation only "wrote" a
|
|
||||||
// type whose creation requires no write. E.g. a coroutine whose initial state
|
|
||||||
// consists solely of uninitialized memory (so it doesn't capture any locals).
|
|
||||||
let value = self.get_const(place)?;
|
|
||||||
if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - {value:?}")) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
trace!("replacing {:?} with {:?}", place, value);
|
|
||||||
|
|
||||||
// FIXME: figure out what to do when read_immediate_raw fails
|
|
||||||
let imm = self.ecx.read_immediate_raw(&value).ok()?;
|
|
||||||
|
|
||||||
let Right(imm) = imm else { return None };
|
|
||||||
match *imm {
|
|
||||||
Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
|
|
||||||
Some(Const::from_scalar(self.tcx, scalar, value.layout.ty))
|
|
||||||
}
|
|
||||||
Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
|
|
||||||
let alloc_id = self
|
|
||||||
.ecx
|
|
||||||
.intern_with_temp_alloc(value.layout, |ecx, dest| {
|
|
||||||
ecx.write_immediate(*imm, dest)
|
|
||||||
})
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
Some(Const::Val(
|
|
||||||
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
|
||||||
value.layout.ty,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// Scalars or scalar pairs that contain undef values are assumed to not have
|
|
||||||
// successfully evaluated and are thus not propagated.
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_not_propagated(&self, local: Local) {
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
assert!(
|
|
||||||
self.get_const(local.into()).is_none()
|
|
||||||
|| self
|
|
||||||
.layout_of(self.local_decls[local].ty)
|
|
||||||
.map_or(true, |layout| layout.is_zst()),
|
|
||||||
"failed to remove values for `{local:?}`, value={:?}",
|
|
||||||
self.get_const(local.into()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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)]
|
||||||
pub enum ConstPropMode {
|
pub enum ConstPropMode {
|
||||||
|
@ -677,154 +324,3 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|
||||||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
|
||||||
self.super_operand(operand, location);
|
|
||||||
if let Some(place) = operand.place()
|
|
||||||
&& let Some(value) = self.replace_with_const(place)
|
|
||||||
{
|
|
||||||
self.patch.before_effect.insert((location, place), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_projection_elem(
|
|
||||||
&mut self,
|
|
||||||
_: PlaceRef<'tcx>,
|
|
||||||
elem: PlaceElem<'tcx>,
|
|
||||||
_: PlaceContext,
|
|
||||||
location: Location,
|
|
||||||
) {
|
|
||||||
if let PlaceElem::Index(local) = elem
|
|
||||||
&& let Some(value) = self.replace_with_const(local.into())
|
|
||||||
{
|
|
||||||
self.patch.before_effect.insert((location, local.into()), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
|
||||||
self.super_assign(place, rvalue, location);
|
|
||||||
|
|
||||||
let Some(()) = self.check_rvalue(rvalue) else {
|
|
||||||
trace!("rvalue check failed, removing const");
|
|
||||||
Self::remove_const(&mut self.ecx, place.local);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.ecx.machine.can_const_prop[place.local] {
|
|
||||||
// Do nothing if the place is indirect.
|
|
||||||
_ if place.is_indirect() => {}
|
|
||||||
ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
|
|
||||||
ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {
|
|
||||||
if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
|
|
||||||
// If this was already an evaluated constant, keep it.
|
|
||||||
if let Rvalue::Use(Operand::Constant(c)) = rvalue
|
|
||||||
&& let Const::Val(..) = c.const_
|
|
||||||
{
|
|
||||||
trace!(
|
|
||||||
"skipping replace of Rvalue::Use({:?} because it is already a const",
|
|
||||||
c
|
|
||||||
);
|
|
||||||
} else if let Some(operand) = self.replace_with_const(*place) {
|
|
||||||
self.patch.assignments.insert(location, operand);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Const prop failed, so erase the destination, ensuring that whatever happens
|
|
||||||
// from here on, does not know about the previous value.
|
|
||||||
// This is important in case we have
|
|
||||||
// ```rust
|
|
||||||
// let mut x = 42;
|
|
||||||
// x = SOME_MUTABLE_STATIC;
|
|
||||||
// // x must now be uninit
|
|
||||||
// ```
|
|
||||||
// FIXME: we overzealously erase the entire local, because that's easier to
|
|
||||||
// implement.
|
|
||||||
trace!(
|
|
||||||
"propagation into {:?} failed.
|
|
||||||
Nuking the entire site from orbit, it's the only way to be sure",
|
|
||||||
place,
|
|
||||||
);
|
|
||||||
Self::remove_const(&mut self.ecx, place.local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
|
||||||
trace!("visit_statement: {:?}", statement);
|
|
||||||
|
|
||||||
// We want to evaluate operands before any change to the assigned-to value,
|
|
||||||
// so we recurse first.
|
|
||||||
self.super_statement(statement, location);
|
|
||||||
|
|
||||||
match statement.kind {
|
|
||||||
StatementKind::SetDiscriminant { ref place, .. } => {
|
|
||||||
match self.ecx.machine.can_const_prop[place.local] {
|
|
||||||
// Do nothing if the place is indirect.
|
|
||||||
_ if place.is_indirect() => {}
|
|
||||||
ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
|
|
||||||
ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => {
|
|
||||||
if self.ecx.statement(statement).is_ok() {
|
|
||||||
trace!("propped discriminant into {:?}", place);
|
|
||||||
} else {
|
|
||||||
Self::remove_const(&mut self.ecx, place.local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatementKind::StorageLive(local) => {
|
|
||||||
Self::remove_const(&mut self.ecx, local);
|
|
||||||
}
|
|
||||||
// We do not need to mark dead locals as such. For `FullConstProp` locals,
|
|
||||||
// this allows to propagate the single assigned value in this case:
|
|
||||||
// ```
|
|
||||||
// let x = SOME_CONST;
|
|
||||||
// if a {
|
|
||||||
// f(copy x);
|
|
||||||
// StorageDead(x);
|
|
||||||
// } else {
|
|
||||||
// g(copy x);
|
|
||||||
// StorageDead(x);
|
|
||||||
// }
|
|
||||||
// ```
|
|
||||||
//
|
|
||||||
// This may propagate a constant where the local would be uninit or dead.
|
|
||||||
// In both cases, this does not matter, as those reads would be UB anyway.
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
|
|
||||||
self.super_basic_block_data(block, data);
|
|
||||||
|
|
||||||
// We remove all Locals which are restricted in propagation to their containing blocks and
|
|
||||||
// which were modified in the current block.
|
|
||||||
// Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
|
|
||||||
let mut written_only_inside_own_block_locals =
|
|
||||||
std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
|
|
||||||
|
|
||||||
// This loop can get very hot for some bodies: it check each local in each bb.
|
|
||||||
// To avoid this quadratic behaviour, we only clear the locals that were modified inside
|
|
||||||
// the current block.
|
|
||||||
for local in written_only_inside_own_block_locals.drain() {
|
|
||||||
debug_assert_eq!(
|
|
||||||
self.ecx.machine.can_const_prop[local],
|
|
||||||
ConstPropMode::OnlyInsideOwnBlock
|
|
||||||
);
|
|
||||||
Self::remove_const(&mut self.ecx, local);
|
|
||||||
}
|
|
||||||
self.ecx.machine.written_only_inside_own_block_locals =
|
|
||||||
written_only_inside_own_block_locals;
|
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() {
|
|
||||||
match mode {
|
|
||||||
ConstPropMode::FullConstProp => {}
|
|
||||||
ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => {
|
|
||||||
self.ensure_not_propagated(local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub struct GVN;
|
||||||
|
|
||||||
impl<'tcx> MirPass<'tcx> for GVN {
|
impl<'tcx> MirPass<'tcx> for GVN {
|
||||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||||
sess.mir_opt_level() >= 4
|
sess.mir_opt_level() >= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self, tcx, body))]
|
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||||
|
|
|
@ -588,7 +588,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
// destroy the SSA property. It should still happen before const-propagation, so the
|
// destroy the SSA property. It should still happen before const-propagation, so the
|
||||||
// latter pass will leverage the created opportunities.
|
// latter pass will leverage the created opportunities.
|
||||||
&separate_const_switch::SeparateConstSwitch,
|
&separate_const_switch::SeparateConstSwitch,
|
||||||
&const_prop::ConstProp,
|
|
||||||
&gvn::GVN,
|
&gvn::GVN,
|
||||||
&simplify::SimplifyLocals::AfterGVN,
|
&simplify::SimplifyLocals::AfterGVN,
|
||||||
&dataflow_const_prop::DataflowConstProp,
|
&dataflow_const_prop::DataflowConstProp,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// compile-flags: -Zmir-enable-passes=+Inline,+ConstProp --crate-type lib
|
// compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib
|
||||||
// revisions: ASSERT NOASSERT
|
// revisions: ASSERT NOASSERT
|
||||||
//[ASSERT] compile-flags: -Coverflow-checks=on
|
//[ASSERT] compile-flags: -Coverflow-checks=on
|
||||||
//[NOASSERT] compile-flags: -Coverflow-checks=off
|
//[NOASSERT] compile-flags: -Coverflow-checks=off
|
||||||
|
|
|
@ -7,19 +7,17 @@ Number of file 0 mappings: 1
|
||||||
- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)
|
- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)
|
||||||
|
|
||||||
Function name: async2::async_func::{closure#0}
|
Function name: async2::async_func::{closure#0}
|
||||||
Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
|
Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
|
||||||
Number of files: 1
|
Number of files: 1
|
||||||
- file 0 => global file 1
|
- file 0 => global file 1
|
||||||
Number of expressions: 2
|
Number of expressions: 1
|
||||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
- expression 0 operands: lhs = Counter(1), rhs = Zero
|
||||||
- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
|
|
||||||
Number of file 0 mappings: 4
|
Number of file 0 mappings: 4
|
||||||
- Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
|
- Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
|
||||||
- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
|
- Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
|
||||||
- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
|
- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
|
||||||
= (c0 - c1)
|
- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
|
||||||
- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
|
= (c1 + Zero)
|
||||||
= (c1 + (c0 - c1))
|
|
||||||
|
|
||||||
Function name: async2::async_func_just_println
|
Function name: async2::async_func_just_println
|
||||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]
|
||||||
|
|
|
@ -25,18 +25,18 @@ Number of file 0 mappings: 2
|
||||||
- Code(Zero) at (prev + 0, 32) to (start + 0, 33)
|
- Code(Zero) at (prev + 0, 32) to (start + 0, 33)
|
||||||
|
|
||||||
Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
|
Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
|
||||||
Raw bytes (22): 0x[01, 01, 04, 07, 0b, 05, 09, 0f, 15, 0d, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
|
Raw bytes (22): 0x[01, 01, 04, 07, 0b, 00, 09, 0f, 15, 00, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
|
||||||
Number of files: 1
|
Number of files: 1
|
||||||
- file 0 => global file 1
|
- file 0 => global file 1
|
||||||
Number of expressions: 4
|
Number of expressions: 4
|
||||||
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
|
- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
|
||||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
- expression 1 operands: lhs = Zero, rhs = Counter(2)
|
||||||
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
|
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
|
||||||
- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
|
- expression 3 operands: lhs = Zero, rhs = Counter(4)
|
||||||
Number of file 0 mappings: 2
|
Number of file 0 mappings: 2
|
||||||
- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
|
- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
|
||||||
- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
|
- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
|
||||||
= ((c1 + c2) + ((c3 + c4) + c5))
|
= ((Zero + c2) + ((Zero + c4) + c5))
|
||||||
|
|
||||||
Function name: <partial_eq::Version as core::fmt::Debug>::fmt
|
Function name: <partial_eq::Version as core::fmt::Debug>::fmt
|
||||||
Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]
|
||||||
|
|
|
@ -103,9 +103,9 @@ pub fn change_iterable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(cfail1,cfail4)))]
|
#[cfg(not(any(cfail1,cfail4)))]
|
||||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
|
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail3")]
|
#[rustc_clean(cfg="cfail3")]
|
||||||
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
|
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail6")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
pub fn change_iterable() {
|
pub fn change_iterable() {
|
||||||
let mut _x = 0;
|
let mut _x = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// revisions: cfail1 cfail2
|
// revisions: cfail1 cfail2
|
||||||
// compile-flags: -Z query-dep-graph
|
// compile-flags: -Z query-dep-graph -Copt-level=0
|
||||||
// build-pass (FIXME(62277): could be check-pass?)
|
// build-pass (FIXME(62277): could be check-pass?)
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// MIR for `main` after ConstProp
|
// MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -7,10 +7,10 @@ fn main() -> () {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
|
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
|
||||||
_1 = (*_2);
|
_1 = (*_2);
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
return;
|
return;
|
|
@ -1,4 +1,4 @@
|
||||||
// MIR for `main` after ConstProp
|
// MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -7,10 +7,10 @@ fn main() -> () {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
|
_2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
|
||||||
_1 = (*_2);
|
_1 = (*_2);
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
return;
|
return;
|
|
@ -1,11 +1,11 @@
|
||||||
// skip-filecheck
|
// skip-filecheck
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// ignore-endian-big
|
// ignore-endian-big
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
static FOO: &[(Option<i32>, &[&str])] =
|
static FOO: &[(Option<i32>, &[&str])] =
|
||||||
&[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];
|
&[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];
|
||||||
|
|
||||||
// EMIT_MIR const_allocation.main.ConstProp.after.mir
|
// EMIT_MIR const_allocation.main.GVN.after.mir
|
||||||
fn main() {
|
fn main() {
|
||||||
FOO;
|
FOO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// MIR for `main` after ConstProp
|
// MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -7,10 +7,10 @@ fn main() -> () {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
|
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
|
||||||
_1 = (*_2);
|
_1 = (*_2);
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
return;
|
return;
|
|
@ -1,4 +1,4 @@
|
||||||
// MIR for `main` after ConstProp
|
// MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -7,10 +7,10 @@ fn main() -> () {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
|
_2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
|
||||||
_1 = (*_2);
|
_1 = (*_2);
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
return;
|
return;
|
|
@ -1,8 +1,8 @@
|
||||||
// skip-filecheck
|
// skip-filecheck
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// ignore-endian-big
|
// ignore-endian-big
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
// EMIT_MIR const_allocation2.main.ConstProp.after.mir
|
// EMIT_MIR const_allocation2.main.GVN.after.mir
|
||||||
fn main() {
|
fn main() {
|
||||||
FOO;
|
FOO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// MIR for `main` after ConstProp
|
// MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -7,10 +7,10 @@ fn main() -> () {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const {ALLOC4: &&Packed};
|
_2 = const {ALLOC4: &&Packed};
|
||||||
_1 = (*_2);
|
_1 = (*_2);
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
return;
|
return;
|
|
@ -1,4 +1,4 @@
|
||||||
// MIR for `main` after ConstProp
|
// MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -7,10 +7,10 @@ fn main() -> () {
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const {ALLOC2: &&Packed};
|
_2 = const {ALLOC2: &&Packed};
|
||||||
_1 = (*_2);
|
_1 = (*_2);
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
return;
|
return;
|
|
@ -1,8 +1,8 @@
|
||||||
// skip-filecheck
|
// skip-filecheck
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// ignore-endian-big
|
// ignore-endian-big
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
// EMIT_MIR const_allocation3.main.ConstProp.after.mir
|
// EMIT_MIR const_allocation3.main.GVN.after.mir
|
||||||
fn main() {
|
fn main() {
|
||||||
FOO;
|
FOO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
debug f => _10;
|
debug f => _10;
|
||||||
let _11: std::option::Option<u16>;
|
let _11: std::option::Option<u16>;
|
||||||
scope 7 {
|
scope 7 {
|
||||||
debug o => _11;
|
- debug o => _11;
|
||||||
|
+ debug o => const Option::<u16>::Some(99_u16);
|
||||||
let _12: Point;
|
let _12: Point;
|
||||||
scope 8 {
|
scope 8 {
|
||||||
- debug p => _12;
|
- debug p => _12;
|
||||||
|
@ -54,11 +55,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
nop;
|
||||||
_1 = const 1_u8;
|
_1 = const 1_u8;
|
||||||
StorageLive(_2);
|
nop;
|
||||||
_2 = const 2_u8;
|
_2 = const 2_u8;
|
||||||
StorageLive(_3);
|
nop;
|
||||||
_3 = const 3_u8;
|
_3 = const 3_u8;
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
|
@ -79,17 +80,17 @@
|
||||||
StorageLive(_10);
|
StorageLive(_10);
|
||||||
_10 = (const true, const false, const 123_u32);
|
_10 = (const true, const false, const 123_u32);
|
||||||
StorageLive(_11);
|
StorageLive(_11);
|
||||||
_11 = Option::<u16>::Some(const 99_u16);
|
_11 = const Option::<u16>::Some(99_u16);
|
||||||
StorageLive(_12);
|
StorageLive(_12);
|
||||||
_12 = const Point {{ x: 32_u32, y: 32_u32 }};
|
_12 = const Point {{ x: 32_u32, y: 32_u32 }};
|
||||||
StorageLive(_13);
|
StorageLive(_13);
|
||||||
StorageLive(_14);
|
nop;
|
||||||
_14 = const 32_u32;
|
_14 = const 32_u32;
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
_15 = const 32_u32;
|
_15 = const 32_u32;
|
||||||
_13 = const 64_u32;
|
_13 = const 64_u32;
|
||||||
StorageDead(_15);
|
StorageDead(_15);
|
||||||
StorageDead(_14);
|
nop;
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_13);
|
StorageDead(_13);
|
||||||
StorageDead(_12);
|
StorageDead(_12);
|
||||||
|
@ -97,9 +98,9 @@
|
||||||
StorageDead(_10);
|
StorageDead(_10);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_3);
|
nop;
|
||||||
StorageDead(_2);
|
nop;
|
||||||
StorageDead(_1);
|
nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,3 +109,7 @@
|
||||||
20 00 00 00 20 00 00 00 │ ... ...
|
20 00 00 00 20 00 00 00 │ ... ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALLOC1 (size: 4, align: 2) {
|
||||||
|
01 00 63 00 │ ..c.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// unit-test: ConstDebugInfo
|
// unit-test: ConstDebugInfo
|
||||||
// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+ConstProp
|
// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN
|
||||||
|
|
||||||
struct Point {
|
struct Point {
|
||||||
x: u32,
|
x: u32,
|
||||||
|
@ -15,7 +15,7 @@ fn main() {
|
||||||
// CHECK: debug sum => const 6_u8;
|
// CHECK: debug sum => const 6_u8;
|
||||||
// CHECK: debug s => const "hello, world!";
|
// CHECK: debug s => const "hello, world!";
|
||||||
// CHECK: debug f => {{_.*}};
|
// CHECK: debug f => {{_.*}};
|
||||||
// CHECK: debug o => {{_.*}};
|
// CHECK: debug o => const Option::<u16>::Some(99_u16);
|
||||||
// CHECK: debug p => const Point
|
// CHECK: debug p => const Point
|
||||||
// CHECK: debug a => const 64_u32;
|
// CHECK: debug a => const 64_u32;
|
||||||
let x = 1u8;
|
let x = 1u8;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `fn0` before ConstProp
|
- // MIR for `fn0` before GVN
|
||||||
+ // MIR for `fn0` after ConstProp
|
+ // MIR for `fn0` after GVN
|
||||||
|
|
||||||
fn fn0() -> bool {
|
fn fn0() -> bool {
|
||||||
let mut _0: bool;
|
let mut _0: bool;
|
||||||
|
@ -23,24 +23,34 @@
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = (const 1_i32, const false);
|
- _2 = (const 1_i32, const false);
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ _2 = const (1_i32, false);
|
||||||
|
+ nop;
|
||||||
_3 = &raw mut (_2.1: bool);
|
_3 = &raw mut (_2.1: bool);
|
||||||
_2 = (const 1_i32, const false);
|
- _2 = (const 1_i32, const false);
|
||||||
|
+ _2 = const (1_i32, false);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
(*_3) = const true;
|
(*_3) = const true;
|
||||||
_4 = const ();
|
_4 = const ();
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
- StorageLive(_5);
|
||||||
|
+ nop;
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = (_2.1: bool);
|
_6 = (_2.1: bool);
|
||||||
_5 = Not(move _6);
|
_5 = Not(move _6);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = _5;
|
_0 = _5;
|
||||||
StorageDead(_5);
|
- StorageDead(_5);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
|
+ nop;
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ALLOC0 (size: 8, align: 4) {
|
||||||
|
+ 01 00 00 00 00 __ __ __ │ .....░░░
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR address_of_pair.fn0.ConstProp.diff
|
// EMIT_MIR address_of_pair.fn0.GVN.diff
|
||||||
pub fn fn0() -> bool {
|
pub fn fn0() -> bool {
|
||||||
// CHECK-LABEL: fn fn0(
|
// CHECK-LABEL: fn fn0(
|
||||||
// CHECK: debug pair => [[pair:_.*]];
|
// CHECK: debug pair => [[pair:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `foo` before ConstProp
|
- // MIR for `foo` before GVN
|
||||||
+ // MIR for `foo` after ConstProp
|
+ // MIR for `foo` after GVN
|
||||||
|
|
||||||
fn foo(_1: u8) -> () {
|
fn foo(_1: u8) -> () {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
|
@ -25,7 +25,8 @@
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = _1;
|
_5 = _1;
|
||||||
_4 = (const 0_i32, move _5);
|
- _4 = (const 0_i32, move _5);
|
||||||
|
+ _4 = (const 0_i32, _1);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
- _3 = (_4.0: i32);
|
- _3 = (_4.0: i32);
|
||||||
- _2 = Add(move _3, const 1_i32);
|
- _2 = Add(move _3, const 1_i32);
|
||||||
|
@ -38,7 +39,8 @@
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
_9 = _1;
|
_9 = _1;
|
||||||
_8 = (move _9, const 1_i32);
|
- _8 = (move _9, const 1_i32);
|
||||||
|
+ _8 = (_1, const 1_i32);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
- _7 = (_8.1: i32);
|
- _7 = (_8.1: i32);
|
||||||
- _6 = Add(move _7, const 2_i32);
|
- _6 = Add(move _7, const 2_i32);
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `foo` before ConstProp
|
- // MIR for `foo` before GVN
|
||||||
+ // MIR for `foo` after ConstProp
|
+ // MIR for `foo` after GVN
|
||||||
|
|
||||||
fn foo(_1: u8) -> () {
|
fn foo(_1: u8) -> () {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
|
@ -25,7 +25,8 @@
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = _1;
|
_5 = _1;
|
||||||
_4 = (const 0_i32, move _5);
|
- _4 = (const 0_i32, move _5);
|
||||||
|
+ _4 = (const 0_i32, _1);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
- _3 = (_4.0: i32);
|
- _3 = (_4.0: i32);
|
||||||
- _2 = Add(move _3, const 1_i32);
|
- _2 = Add(move _3, const 1_i32);
|
||||||
|
@ -38,7 +39,8 @@
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
StorageLive(_9);
|
StorageLive(_9);
|
||||||
_9 = _1;
|
_9 = _1;
|
||||||
_8 = (move _9, const 1_i32);
|
- _8 = (move _9, const 1_i32);
|
||||||
|
+ _8 = (_1, const 1_i32);
|
||||||
StorageDead(_9);
|
StorageDead(_9);
|
||||||
- _7 = (_8.1: i32);
|
- _7 = (_8.1: i32);
|
||||||
- _6 = Add(move _7, const 2_i32);
|
- _6 = Add(move _7, const 2_i32);
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -13,7 +13,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = (const 0_i32, const 1_u8, const 2_i32);
|
_3 = (const 0_i32, const 1_u8, const 2_i32);
|
||||||
|
@ -35,7 +36,8 @@
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -13,7 +13,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = (const 0_i32, const 1_u8, const 2_i32);
|
_3 = (const 0_i32, const 1_u8, const 2_i32);
|
||||||
|
@ -35,7 +36,8 @@
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -O
|
// compile-flags: -O
|
||||||
|
|
||||||
// EMIT_MIR aggregate.main.ConstProp.diff
|
// EMIT_MIR aggregate.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
@ -15,7 +15,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that we still propagate if part of the aggregate is not known.
|
// Verify that we still propagate if part of the aggregate is not known.
|
||||||
// EMIT_MIR aggregate.foo.ConstProp.diff
|
// EMIT_MIR aggregate.foo.GVN.diff
|
||||||
fn foo(x: u8) {
|
fn foo(x: u8) {
|
||||||
// CHECK-LABEL: fn foo(
|
// CHECK-LABEL: fn foo(
|
||||||
// CHECK: debug first => [[first:_.*]];
|
// CHECK: debug first => [[first:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,12 +18,11 @@
|
||||||
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
||||||
+ _4 = const 4_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,12 +18,11 @@
|
||||||
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
||||||
+ _4 = const 4_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,12 +18,11 @@
|
||||||
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
||||||
+ _4 = const 4_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,12 +18,11 @@
|
||||||
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
_2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
||||||
+ _4 = const 4_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
|
@ -1,8 +1,8 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
|
|
||||||
// EMIT_MIR array_index.main.ConstProp.diff
|
// EMIT_MIR array_index.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
_1 = const 0_i32;
|
_1 = const 0_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
|
@ -47,7 +48,8 @@
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
_1 = const 0_i32;
|
_1 = const 0_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
|
@ -47,7 +48,8 @@
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
|
|
||||||
// EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
|
// EMIT_MIR bad_op_div_by_zero.main.GVN.diff
|
||||||
#[allow(unconditional_panic)]
|
#[allow(unconditional_panic)]
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
_1 = const 0_i32;
|
_1 = const 0_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
|
@ -47,7 +48,8 @@
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
_1 = const 0_i32;
|
_1 = const 0_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
|
@ -47,7 +48,8 @@
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
|
|
||||||
// EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
|
// EMIT_MIR bad_op_mod_by_zero.main.GVN.diff
|
||||||
#[allow(unconditional_panic)]
|
#[allow(unconditional_panic)]
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,15 +22,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
_9 = const _;
|
_9 = const _;
|
||||||
_3 = &(*_9);
|
_3 = &(*_9);
|
||||||
_2 = &raw const (*_3);
|
_2 = &raw const (*_3);
|
||||||
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = const 3_usize;
|
_6 = const 3_usize;
|
||||||
|
@ -47,7 +50,8 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,15 +22,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
_9 = const _;
|
_9 = const _;
|
||||||
_3 = &(*_9);
|
_3 = &(*_9);
|
||||||
_2 = &raw const (*_3);
|
_2 = &raw const (*_3);
|
||||||
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = const 3_usize;
|
_6 = const 3_usize;
|
||||||
|
@ -47,7 +50,8 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,15 +22,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
_9 = const _;
|
_9 = const _;
|
||||||
_3 = &(*_9);
|
_3 = &(*_9);
|
||||||
_2 = &raw const (*_3);
|
_2 = &raw const (*_3);
|
||||||
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = const 3_usize;
|
_6 = const 3_usize;
|
||||||
|
@ -47,7 +50,8 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,15 +22,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
_9 = const _;
|
_9 = const _;
|
||||||
_3 = &(*_9);
|
_3 = &(*_9);
|
||||||
_2 = &raw const (*_3);
|
_2 = &raw const (*_3);
|
||||||
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
_1 = move _2 as *const [i32] (PointerCoercion(Unsize));
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = const 3_usize;
|
_6 = const 3_usize;
|
||||||
|
@ -47,7 +50,8 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
|
|
||||||
// EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
|
// EMIT_MIR bad_op_unsafe_oob_for_slices.main.GVN.diff
|
||||||
#[allow(unconditional_panic)]
|
#[allow(unconditional_panic)]
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR boolean_identities.test.ConstProp.diff
|
// EMIT_MIR boolean_identities.test.GVN.diff
|
||||||
pub fn test(x: bool, y: bool) -> bool {
|
pub fn test(x: bool, y: bool) -> bool {
|
||||||
// CHECK-LABEL: fn test(
|
// CHECK-LABEL: fn test(
|
||||||
// CHECK: debug a => [[a:_.*]];
|
// CHECK: debug a => [[a:_.*]];
|
||||||
// CHECK: debug b => [[b:_.*]];
|
// CHECK: debug b => [[b:_.*]];
|
||||||
// CHECK: [[a]] = const true;
|
// FIXME(cjgillot) simplify algebraic identity
|
||||||
// CHECK: [[b]] = const false;
|
// CHECK-NOT: [[a]] = const true;
|
||||||
// CHECK: _0 = const false;
|
// CHECK-NOT: [[b]] = const false;
|
||||||
|
// CHECK-NOT: _0 = const false;
|
||||||
let a = (y | true);
|
let a = (y | true);
|
||||||
let b = (x & false);
|
let b = (x & false);
|
||||||
a & b
|
a & b
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `test` before ConstProp
|
- // MIR for `test` before GVN
|
||||||
+ // MIR for `test` after ConstProp
|
+ // MIR for `test` after GVN
|
||||||
|
|
||||||
fn test(_1: bool, _2: bool) -> bool {
|
fn test(_1: bool, _2: bool) -> bool {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
|
@ -19,30 +19,32 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = _2;
|
_4 = _2;
|
||||||
- _3 = BitOr(move _4, const true);
|
- _3 = BitOr(move _4, const true);
|
||||||
+ _3 = const true;
|
+ _3 = BitOr(_2, const true);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
- StorageLive(_5);
|
||||||
|
+ nop;
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = _1;
|
_6 = _1;
|
||||||
- _5 = BitAnd(move _6, const false);
|
- _5 = BitAnd(move _6, const false);
|
||||||
+ _5 = const false;
|
+ _5 = BitAnd(_1, const false);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
- _7 = _3;
|
_7 = _3;
|
||||||
+ _7 = const true;
|
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
- _8 = _5;
|
_8 = _5;
|
||||||
- _0 = BitAnd(move _7, move _8);
|
- _0 = BitAnd(move _7, move _8);
|
||||||
+ _8 = const false;
|
+ _0 = BitAnd(_3, _5);
|
||||||
+ _0 = const false;
|
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_5);
|
- StorageDead(_5);
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,4 +1,4 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -O
|
// compile-flags: -O
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
// Note: this test verifies that we, in fact, do not const prop `#[rustc_box]`
|
// Note: this test verifies that we, in fact, do not const prop `#[rustc_box]`
|
||||||
|
|
||||||
// EMIT_MIR boxes.main.ConstProp.diff
|
// EMIT_MIR boxes.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// EMIT_MIR cast.main.ConstProp.diff
|
// EMIT_MIR cast.main.GVN.diff
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,8 +1,8 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -C overflow-checks=on
|
// compile-flags: -C overflow-checks=on
|
||||||
|
|
||||||
// EMIT_MIR checked_add.main.ConstProp.diff
|
// EMIT_MIR checked_add.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `hello` before ConstProp
|
- // MIR for `hello` before GVN
|
||||||
+ // MIR for `hello` after ConstProp
|
+ // MIR for `hello` after GVN
|
||||||
|
|
||||||
fn hello() -> () {
|
fn hello() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -8,9 +8,8 @@
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
- _1 = const _;
|
_1 = const _;
|
||||||
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
|
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
|
||||||
+ _1 = const false;
|
|
||||||
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
|
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `hello` before ConstProp
|
- // MIR for `hello` before GVN
|
||||||
+ // MIR for `hello` after ConstProp
|
+ // MIR for `hello` after GVN
|
||||||
|
|
||||||
fn hello() -> () {
|
fn hello() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -8,9 +8,8 @@
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
- _1 = const _;
|
_1 = const _;
|
||||||
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
|
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
|
||||||
+ _1 = const false;
|
|
||||||
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
|
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// skip-filecheck
|
// skip-filecheck
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -Zmir-opt-level=1
|
// compile-flags: -Zmir-opt-level=1
|
||||||
|
|
||||||
trait NeedsDrop: Sized {
|
trait NeedsDrop: Sized {
|
||||||
|
@ -9,7 +9,7 @@ trait NeedsDrop: Sized {
|
||||||
|
|
||||||
impl<This> NeedsDrop for This {}
|
impl<This> NeedsDrop for This {}
|
||||||
|
|
||||||
// EMIT_MIR control_flow_simplification.hello.ConstProp.diff
|
// EMIT_MIR control_flow_simplification.hello.GVN.diff
|
||||||
// EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
|
// EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
|
||||||
fn hello<T>(){
|
fn hello<T>(){
|
||||||
if <bool>::NEEDS {
|
if <bool>::NEEDS {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,4 +1,4 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
|
// FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
|
||||||
// `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect`
|
// `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect`
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
// Fixing either of those will allow us to const-prop this away.
|
// Fixing either of those will allow us to const-prop this away.
|
||||||
|
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
// EMIT_MIR discriminant.main.ConstProp.diff
|
// EMIT_MIR discriminant.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: bb0: {
|
// CHECK: bb0: {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,8 +1,8 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -C overflow-checks=on
|
// compile-flags: -C overflow-checks=on
|
||||||
|
|
||||||
// EMIT_MIR indirect.main.ConstProp.diff
|
// EMIT_MIR indirect.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `bar` before ConstProp
|
- // MIR for `bar` before GVN
|
||||||
+ // MIR for `bar` after ConstProp
|
+ // MIR for `bar` after GVN
|
||||||
|
|
||||||
fn bar() -> () {
|
fn bar() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -19,12 +19,15 @@
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
_1 = (const 1_i32,);
|
- _1 = (const 1_i32,);
|
||||||
|
+ _1 = const (1_i32,);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
- StorageLive(_3);
|
||||||
|
+ nop;
|
||||||
_3 = &raw mut (_1.0: i32);
|
_3 = &raw mut (_1.0: i32);
|
||||||
(*_3) = const 5_i32;
|
(*_3) = const 5_i32;
|
||||||
StorageDead(_3);
|
- StorageDead(_3);
|
||||||
|
+ nop;
|
||||||
_2 = const ();
|
_2 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `foo` before ConstProp
|
- // MIR for `foo` before GVN
|
||||||
+ // MIR for `foo` after ConstProp
|
+ // MIR for `foo` after GVN
|
||||||
|
|
||||||
fn foo() -> () {
|
fn foo() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -16,11 +16,14 @@
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
_1 = (const 1_i32,);
|
- _1 = (const 1_i32,);
|
||||||
StorageLive(_2);
|
- StorageLive(_2);
|
||||||
|
+ _1 = const (1_i32,);
|
||||||
|
+ nop;
|
||||||
_2 = &mut (_1.0: i32);
|
_2 = &mut (_1.0: i32);
|
||||||
(*_2) = const 5_i32;
|
(*_2) = const 5_i32;
|
||||||
StorageDead(_2);
|
- StorageDead(_2);
|
||||||
|
+ nop;
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = (_1.0: i32);
|
_4 = (_1.0: i32);
|
|
@ -1,13 +1,13 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// Check that we do not propagate past an indirect mutation.
|
// Check that we do not propagate past an indirect mutation.
|
||||||
#![feature(raw_ref_op)]
|
#![feature(raw_ref_op)]
|
||||||
|
|
||||||
// EMIT_MIR indirect_mutation.foo.ConstProp.diff
|
// EMIT_MIR indirect_mutation.foo.GVN.diff
|
||||||
fn foo() {
|
fn foo() {
|
||||||
// CHECK-LABEL: fn foo(
|
// CHECK-LABEL: fn foo(
|
||||||
// CHECK: debug u => _1;
|
// CHECK: debug u => _1;
|
||||||
// CHECK: debug y => _3;
|
// CHECK: debug y => _3;
|
||||||
// CHECK: _1 = (const 1_i32,);
|
// CHECK: _1 = const (1_i32,);
|
||||||
// CHECK: _2 = &mut (_1.0: i32);
|
// CHECK: _2 = &mut (_1.0: i32);
|
||||||
// CHECK: (*_2) = const 5_i32;
|
// CHECK: (*_2) = const 5_i32;
|
||||||
// CHECK: _4 = (_1.0: i32);
|
// CHECK: _4 = (_1.0: i32);
|
||||||
|
@ -18,7 +18,7 @@ fn foo() {
|
||||||
let y = { u.0 } == 5;
|
let y = { u.0 } == 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EMIT_MIR indirect_mutation.bar.ConstProp.diff
|
// EMIT_MIR indirect_mutation.bar.GVN.diff
|
||||||
fn bar() {
|
fn bar() {
|
||||||
// CHECK-LABEL: fn bar(
|
// CHECK-LABEL: fn bar(
|
||||||
// CHECK: debug v => _1;
|
// CHECK: debug v => _1;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,10 +1,10 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -Zmir-enable-passes=+Inline
|
// compile-flags: -Zmir-enable-passes=+Inline
|
||||||
|
|
||||||
// After inlining, this will contain a `CheckedBinaryOp`.
|
// After inlining, this will contain a `CheckedBinaryOp`.
|
||||||
// Propagating the overflow is ok as codegen will just skip emitting the panic.
|
// Propagating the overflow is ok as codegen will just skip emitting the panic.
|
||||||
// EMIT_MIR inherit_overflow.main.ConstProp.diff
|
// EMIT_MIR inherit_overflow.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: {{_.*}} = const (0_u8, true);
|
// CHECK: {{_.*}} = const (0_u8, true);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -35,17 +35,14 @@
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = InvalidChar { int: const 1114113_u32 };
|
_2 = InvalidChar { int: const 1114113_u32 };
|
||||||
- _1 = (_2.1: char);
|
_1 = (_2.1: char);
|
||||||
+ _1 = const {transmute(0x00110001): char};
|
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
_5 = InvalidTag { int: const 4_u32 };
|
_5 = InvalidTag { int: const 4_u32 };
|
||||||
- _4 = (_5.1: E);
|
_4 = (_5.1: E);
|
||||||
- _3 = [move _4];
|
_3 = [move _4];
|
||||||
+ _4 = const Scalar(0x00000004): E;
|
|
||||||
+ _3 = [const Scalar(0x00000004): E];
|
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
nop;
|
nop;
|
|
@ -1,5 +1,5 @@
|
||||||
// skip-filecheck
|
// skip-filecheck
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// compile-flags: -Zmir-enable-passes=+RemoveZsts
|
// compile-flags: -Zmir-enable-passes=+RemoveZsts
|
||||||
// Verify that we can pretty print invalid constants.
|
// Verify that we can pretty print invalid constants.
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ enum E { A, B, C }
|
||||||
enum Empty {}
|
enum Empty {}
|
||||||
|
|
||||||
// EMIT_MIR invalid_constant.main.RemoveZsts.diff
|
// EMIT_MIR invalid_constant.main.RemoveZsts.diff
|
||||||
// EMIT_MIR invalid_constant.main.ConstProp.diff
|
// EMIT_MIR invalid_constant.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// An invalid char.
|
// An invalid char.
|
||||||
union InvalidChar {
|
union InvalidChar {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -11,8 +11,9 @@
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = ();
|
- _3 = ();
|
||||||
- _2 = (move _3, const 0_u8, const 0_u8);
|
- _2 = (move _3, const 0_u8, const 0_u8);
|
||||||
|
+ _3 = const ();
|
||||||
+ _2 = const ((), 0_u8, 0_u8);
|
+ _2 = const ((), 0_u8, 0_u8);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
- _1 = encode(move _2) -> [return: bb1, unwind unreachable];
|
- _1 = encode(move _2) -> [return: bb1, unwind unreachable];
|
||||||
|
@ -28,10 +29,6 @@
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ ALLOC0 (size: 2, align: 1) {
|
+ ALLOC0 (size: 2, align: 1) {
|
||||||
+ 00 00 │ ..
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ALLOC1 (size: 2, align: 1) {
|
|
||||||
+ 00 00 │ ..
|
+ 00 00 │ ..
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -11,8 +11,9 @@
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = ();
|
- _3 = ();
|
||||||
- _2 = (move _3, const 0_u8, const 0_u8);
|
- _2 = (move _3, const 0_u8, const 0_u8);
|
||||||
|
+ _3 = const ();
|
||||||
+ _2 = const ((), 0_u8, 0_u8);
|
+ _2 = const ((), 0_u8, 0_u8);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
- _1 = encode(move _2) -> [return: bb1, unwind continue];
|
- _1 = encode(move _2) -> [return: bb1, unwind continue];
|
||||||
|
@ -28,10 +29,6 @@
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ ALLOC0 (size: 2, align: 1) {
|
+ ALLOC0 (size: 2, align: 1) {
|
||||||
+ 00 00 │ ..
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ALLOC1 (size: 2, align: 1) {
|
|
||||||
+ 00 00 │ ..
|
+ 00 00 │ ..
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
|
// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
|
||||||
// outputs below, after ConstProp this is how _2 would look like with the bug:
|
// outputs below, after GVN this is how _2 would look like with the bug:
|
||||||
//
|
//
|
||||||
// _2 = (const Scalar(0x00) : (), const 0u8);
|
// _2 = (const Scalar(0x00) : (), const 0u8);
|
||||||
//
|
//
|
||||||
|
@ -12,7 +12,7 @@ fn encode(this: ((), u8, u8)) {
|
||||||
assert!(this.2 == 0);
|
assert!(this.2 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EMIT_MIR issue_66971.main.ConstProp.diff
|
// EMIT_MIR issue_66971.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: = encode(const ((), 0_u8, 0_u8))
|
// CHECK: = encode(const ((), 0_u8, 0_u8))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// This used to ICE in const-prop
|
// This used to ICE in const-prop
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ fn test(this: ((u8, u8),)) {
|
||||||
assert!((this.0).0 == 1);
|
assert!((this.0).0 == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EMIT_MIR issue_67019.main.ConstProp.diff
|
// EMIT_MIR issue_67019.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: = test(const ((1_u8, 2_u8),))
|
// CHECK: = test(const ((1_u8, 2_u8),))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,17 +18,16 @@
|
||||||
_2 = [const 0_u8; 5000];
|
_2 = [const 0_u8; 5000];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
||||||
+ _4 = const 5000_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
- _1 = _2[_3];
|
- _1 = _2[_3];
|
||||||
+ _1 = _2[2 of 3];
|
+ _1 = const 0_u8;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,17 +18,16 @@
|
||||||
_2 = [const 0_u8; 5000];
|
_2 = [const 0_u8; 5000];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
||||||
+ _4 = const 5000_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
- _1 = _2[_3];
|
- _1 = _2[_3];
|
||||||
+ _1 = _2[2 of 3];
|
+ _1 = const 0_u8;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,17 +18,16 @@
|
||||||
_2 = [const 0_u8; 5000];
|
_2 = [const 0_u8; 5000];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
|
||||||
+ _4 = const 5000_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
- _1 = _2[_3];
|
- _1 = _2[_3];
|
||||||
+ _1 = _2[2 of 3];
|
+ _1 = const 0_u8;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,17 +18,16 @@
|
||||||
_2 = [const 0_u8; 5000];
|
_2 = [const 0_u8; 5000];
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = const 2_usize;
|
_3 = const 2_usize;
|
||||||
- _4 = Len(_2);
|
_4 = Len(_2);
|
||||||
- _5 = Lt(_3, _4);
|
- _5 = Lt(_3, _4);
|
||||||
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
|
||||||
+ _4 = const 5000_usize;
|
+ _5 = Lt(const 2_usize, _4);
|
||||||
+ _5 = const true;
|
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
|
||||||
+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
- _1 = _2[_3];
|
- _1 = _2[_3];
|
||||||
+ _1 = _2[2 of 3];
|
+ _1 = const 0_u8;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
_0 = const ();
|
_0 = const ();
|
|
@ -1,9 +1,9 @@
|
||||||
// skip-filecheck
|
// skip-filecheck
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
|
|
||||||
// EMIT_MIR large_array_index.main.ConstProp.diff
|
// EMIT_MIR large_array_index.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// check that we don't propagate this, because it's too large
|
// check that we don't propagate this, because it's too large
|
||||||
let x: u8 = [0_u8; 5000][2];
|
let x: u8 = [0_u8; 5000][2];
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR mult_by_zero.test.ConstProp.diff
|
// EMIT_MIR mult_by_zero.test.GVN.diff
|
||||||
fn test(x: i32) -> i32 {
|
fn test(x: i32) -> i32 {
|
||||||
// CHECK: fn test(
|
// CHECK: fn test(
|
||||||
// CHECK: _0 = const 0_i32;
|
// FIXME(cjgillot) simplify algebraic identity
|
||||||
|
// CHECK-NOT: _0 = const 0_i32;
|
||||||
x * 0
|
x * 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `test` before ConstProp
|
- // MIR for `test` before GVN
|
||||||
+ // MIR for `test` after ConstProp
|
+ // MIR for `test` after GVN
|
||||||
|
|
||||||
fn test(_1: i32) -> i32 {
|
fn test(_1: i32) -> i32 {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = _1;
|
_2 = _1;
|
||||||
- _0 = Mul(move _2, const 0_i32);
|
- _0 = Mul(move _2, const 0_i32);
|
||||||
+ _0 = const 0_i32;
|
+ _0 = Mul(_1, const 0_i32);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -17,8 +17,7 @@
|
||||||
_1 = const 42_i32;
|
_1 = const 42_i32;
|
||||||
_1 = const 99_i32;
|
_1 = const 99_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
- _2 = _1;
|
_2 = _1;
|
||||||
+ _2 = const 99_i32;
|
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
|
@ -1,13 +1,13 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR mutable_variable.main.ConstProp.diff
|
// EMIT_MIR mutable_variable.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
// CHECK: debug y => [[y:_.*]];
|
// CHECK: debug y => [[y:_.*]];
|
||||||
// CHECK: [[x]] = const 42_i32;
|
// CHECK: [[x]] = const 42_i32;
|
||||||
// CHECK: [[x]] = const 99_i32;
|
// CHECK: [[x]] = const 99_i32;
|
||||||
// CHECK: [[y]] = const 99_i32;
|
// CHECK: [[y]] = [[x]];
|
||||||
let mut x = 42;
|
let mut x = 42;
|
||||||
x = 99;
|
x = 99;
|
||||||
let y = x;
|
let y = x;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,8 +18,7 @@
|
||||||
+ _1 = const (42_i32, 43_i32);
|
+ _1 = const (42_i32, 43_i32);
|
||||||
(_1.1: i32) = const 99_i32;
|
(_1.1: i32) = const 99_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
- _2 = _1;
|
_2 = _1;
|
||||||
+ _2 = const (42_i32, 99_i32);
|
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
|
@ -28,10 +27,6 @@
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ ALLOC0 (size: 8, align: 4) {
|
+ ALLOC0 (size: 8, align: 4) {
|
||||||
+ 2a 00 00 00 63 00 00 00 │ *...c...
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ALLOC1 (size: 8, align: 4) {
|
|
||||||
+ 2a 00 00 00 2b 00 00 00 │ *...+...
|
+ 2a 00 00 00 2b 00 00 00 │ *...+...
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR mutable_variable_aggregate.main.ConstProp.diff
|
// EMIT_MIR mutable_variable_aggregate.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
// CHECK: debug y => [[y:_.*]];
|
// CHECK: debug y => [[y:_.*]];
|
||||||
// CHECK: [[x]] = const (42_i32, 43_i32);
|
// CHECK: [[x]] = const (42_i32, 43_i32);
|
||||||
// CHECK: ([[x]].1: i32) = const 99_i32;
|
// CHECK: ([[x]].1: i32) = const 99_i32;
|
||||||
// CHECK: [[y]] = const (42_i32, 99_i32);
|
// CHECK: [[y]] = [[x]];
|
||||||
let mut x = (42, 43);
|
let mut x = (42, 43);
|
||||||
x.1 = 99;
|
x.1 = 99;
|
||||||
let y = x;
|
let y = x;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -18,17 +18,24 @@
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
_1 = (const 42_i32, const 43_i32);
|
- _1 = (const 42_i32, const 43_i32);
|
||||||
StorageLive(_2);
|
- StorageLive(_2);
|
||||||
|
+ _1 = const (42_i32, 43_i32);
|
||||||
|
+ nop;
|
||||||
_2 = &mut _1;
|
_2 = &mut _1;
|
||||||
((*_2).1: i32) = const 99_i32;
|
((*_2).1: i32) = const 99_i32;
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = _1;
|
_3 = _1;
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_2);
|
- StorageDead(_2);
|
||||||
|
+ nop;
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ALLOC0 (size: 8, align: 4) {
|
||||||
|
+ 2a 00 00 00 2b 00 00 00 │ *...+...
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR mutable_variable_aggregate_mut_ref.main.ConstProp.diff
|
// EMIT_MIR mutable_variable_aggregate_mut_ref.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
// CHECK: debug z => [[z:_.*]];
|
// CHECK: debug z => [[z:_.*]];
|
||||||
// CHECK: debug y => [[y:_.*]];
|
// CHECK: debug y => [[y:_.*]];
|
||||||
// CHECK: [[x]] = (const 42_i32, const 43_i32);
|
// CHECK: [[x]] = const (42_i32, 43_i32);
|
||||||
// CHECK: [[z]] = &mut [[x]];
|
// CHECK: [[z]] = &mut [[x]];
|
||||||
// CHECK: ((*[[z]]).1: i32) = const 99_i32;
|
// CHECK: ((*[[z]]).1: i32) = const 99_i32;
|
||||||
// CHECK: [[y]] = [[x]];
|
// CHECK: [[y]] = [[x]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -21,8 +21,7 @@
|
||||||
(_1.1: i32) = const 99_i32;
|
(_1.1: i32) = const 99_i32;
|
||||||
(_1.0: i32) = const 42_i32;
|
(_1.0: i32) = const 42_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
- _2 = (_1.1: i32);
|
_2 = (_1.1: i32);
|
||||||
+ _2 = const 99_i32;
|
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -21,8 +21,7 @@
|
||||||
(_1.1: i32) = const 99_i32;
|
(_1.1: i32) = const 99_i32;
|
||||||
(_1.0: i32) = const 42_i32;
|
(_1.0: i32) = const 42_i32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
- _2 = (_1.1: i32);
|
_2 = (_1.1: i32);
|
||||||
+ _2 = const 99_i32;
|
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
StorageDead(_1);
|
|
@ -1,7 +1,7 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR mutable_variable_aggregate_partial_read.main.ConstProp.diff
|
// EMIT_MIR mutable_variable_aggregate_partial_read.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
@ -9,7 +9,7 @@ fn main() {
|
||||||
// CHECK: [[x]] = foo()
|
// CHECK: [[x]] = foo()
|
||||||
// CHECK: ([[x]].1: i32) = const 99_i32;
|
// CHECK: ([[x]].1: i32) = const 99_i32;
|
||||||
// CHECK: ([[x]].0: i32) = const 42_i32;
|
// CHECK: ([[x]].0: i32) = const 42_i32;
|
||||||
// CHECK: [[y]] = const 99_i32;
|
// CHECK: [[y]] = ([[x]].1: i32);
|
||||||
let mut x: (i32, i32) = foo();
|
let mut x: (i32, i32) = foo();
|
||||||
x.1 = 99;
|
x.1 = 99;
|
||||||
x.0 = 42;
|
x.0 = 42;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,12 +22,14 @@
|
||||||
_1 = const 42_u32;
|
_1 = const 42_u32;
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
- StorageLive(_4);
|
||||||
|
+ nop;
|
||||||
_4 = const {ALLOC0: *mut u32};
|
_4 = const {ALLOC0: *mut u32};
|
||||||
_3 = (*_4);
|
_3 = (*_4);
|
||||||
_1 = move _3;
|
_1 = move _3;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageDead(_4);
|
- StorageDead(_4);
|
||||||
|
+ nop;
|
||||||
_2 = const ();
|
_2 = const ();
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
|
@ -1,9 +1,9 @@
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// Verify that we do not propagate the contents of this mutable static.
|
// Verify that we do not propagate the contents of this mutable static.
|
||||||
static mut STATIC: u32 = 0x42424242;
|
static mut STATIC: u32 = 0x42424242;
|
||||||
|
|
||||||
// EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff
|
// EMIT_MIR mutable_variable_no_prop.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug x => [[x:_.*]];
|
// CHECK: debug x => [[x:_.*]];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,7 +22,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
_1 = foo() -> [return: bb1, unwind unreachable];
|
_1 = foo() -> [return: bb1, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,18 +33,19 @@
|
||||||
+ _2 = const (1_i32, 2_i32);
|
+ _2 = const (1_i32, 2_i32);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = _1;
|
_3 = _1;
|
||||||
(_2.1: i32) = move _3;
|
- (_2.1: i32) = move _3;
|
||||||
|
+ (_2.1: i32) = _1;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = (_2.1: i32);
|
_4 = (_2.1: i32);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
- _5 = (_2.0: i32);
|
_5 = (_2.0: i32);
|
||||||
+ _5 = const 1_i32;
|
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
+ }
|
+ }
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `main` before ConstProp
|
- // MIR for `main` before GVN
|
||||||
+ // MIR for `main` after ConstProp
|
+ // MIR for `main` after GVN
|
||||||
|
|
||||||
fn main() -> () {
|
fn main() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -22,7 +22,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1);
|
- StorageLive(_1);
|
||||||
|
+ nop;
|
||||||
_1 = foo() -> [return: bb1, unwind continue];
|
_1 = foo() -> [return: bb1, unwind continue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,18 +33,19 @@
|
||||||
+ _2 = const (1_i32, 2_i32);
|
+ _2 = const (1_i32, 2_i32);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
_3 = _1;
|
_3 = _1;
|
||||||
(_2.1: i32) = move _3;
|
- (_2.1: i32) = move _3;
|
||||||
|
+ (_2.1: i32) = _1;
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = (_2.1: i32);
|
_4 = (_2.1: i32);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
- _5 = (_2.0: i32);
|
_5 = (_2.0: i32);
|
||||||
+ _5 = const 1_i32;
|
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageDead(_1);
|
- StorageDead(_1);
|
||||||
|
+ nop;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
+ }
|
+ }
|
|
@ -1,7 +1,7 @@
|
||||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||||
// unit-test: ConstProp
|
// unit-test: GVN
|
||||||
|
|
||||||
// EMIT_MIR mutable_variable_unprop_assign.main.ConstProp.diff
|
// EMIT_MIR mutable_variable_unprop_assign.main.GVN.diff
|
||||||
fn main() {
|
fn main() {
|
||||||
// CHECK-LABEL: fn main(
|
// CHECK-LABEL: fn main(
|
||||||
// CHECK: debug a => [[a:_.*]];
|
// CHECK: debug a => [[a:_.*]];
|
||||||
|
@ -10,10 +10,9 @@ fn main() {
|
||||||
// CHECK: debug z => [[z:_.*]];
|
// CHECK: debug z => [[z:_.*]];
|
||||||
// CHECK: [[a]] = foo()
|
// CHECK: [[a]] = foo()
|
||||||
// CHECK: [[x]] = const (1_i32, 2_i32);
|
// CHECK: [[x]] = const (1_i32, 2_i32);
|
||||||
// CHECK: [[tmp:_.*]] = [[a]];
|
// CHECK: ([[x]].1: i32) = [[a]];
|
||||||
// CHECK: ([[x]].1: i32) = move [[tmp]];
|
|
||||||
// CHECK: [[y]] = ([[x]].1: i32);
|
// CHECK: [[y]] = ([[x]].1: i32);
|
||||||
// CHECK: [[z]] = const 1_i32;
|
// CHECK: [[z]] = ([[x]].0: i32);
|
||||||
let a = foo();
|
let a = foo();
|
||||||
let mut x: (i32, i32) = (1, 2);
|
let mut x: (i32, i32) = (1, 2);
|
||||||
x.1 = a;
|
x.1 = a;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `concrete` before ConstProp
|
- // MIR for `concrete` before GVN
|
||||||
+ // MIR for `concrete` after ConstProp
|
+ // MIR for `concrete` after GVN
|
||||||
|
|
||||||
fn concrete() -> () {
|
fn concrete() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `concrete` before ConstProp
|
- // MIR for `concrete` before GVN
|
||||||
+ // MIR for `concrete` after ConstProp
|
+ // MIR for `concrete` after GVN
|
||||||
|
|
||||||
fn concrete() -> () {
|
fn concrete() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
|
@ -1,5 +1,5 @@
|
||||||
- // MIR for `generic` before ConstProp
|
- // MIR for `generic` before GVN
|
||||||
+ // MIR for `generic` after ConstProp
|
+ // MIR for `generic` after GVN
|
||||||
|
|
||||||
fn generic() -> () {
|
fn generic() -> () {
|
||||||
let mut _0: ();
|
let mut _0: ();
|
||||||
|
@ -58,16 +58,20 @@
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = OffsetOf(Delta<T>, [(0, 1)]);
|
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
|
||||||
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||||
|
+ _6 = const 0_usize;
|
||||||
|
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = OffsetOf(Delta<T>, [(0, 2)]);
|
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
|
||||||
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||||
|
+ _8 = const 2_usize;
|
||||||
|
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue