Auto merge of #132527 - DianQK:gvn-stmt-iter, r=oli-obk
gvn: Invalid dereferences for all non-local mutations Fixes #132353. This PR removes the computation value by traversing SSA locals through `for_each_assignment_mut`. Because the `for_each_assignment_mut` traversal skips statements which have side effects, such as dereference assignments, the computation may be unsound. Instead of `for_each_assignment_mut`, we compute values by traversing in reverse postorder. Because we compute and use the symbolic representation of values on the fly, I invalidate all old values when encountering a dereference assignment. The current approach does not prevent the optimization of a clone to a copy. In the future, we may add an alias model, or dominance information for dereference assignments, or SSA form to help GVN. r? cjgillot cc `@jieyouxu` #132356 cc `@RalfJung` #133474
This commit is contained in:
commit
00095b3da4
43 changed files with 567 additions and 574 deletions
|
@ -9,6 +9,8 @@ pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
|||
pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>;
|
||||
pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>;
|
||||
|
||||
pub use indexmap::set::MutableValues;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_id_collections {
|
||||
($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => {
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
//! MIR may contain repeated and/or redundant computations. The objective of this pass is to detect
|
||||
//! such redundancies and re-use the already-computed result when possible.
|
||||
//!
|
||||
//! In a first pass, we compute a symbolic representation of values that are assigned to SSA
|
||||
//! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of
|
||||
//! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
|
||||
//!
|
||||
//! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available
|
||||
//! values, the locals in which they are stored, and the assignment location.
|
||||
//!
|
||||
//! In a second pass, we traverse all (non SSA) assignments `x = rvalue` and operands. For each
|
||||
//! We traverse all assignments `x = rvalue` and operands.
|
||||
//!
|
||||
//! For each SSA one, we compute a symbolic representation of values that are assigned to SSA
|
||||
//! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of
|
||||
//! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
|
||||
//!
|
||||
//! For each non-SSA
|
||||
//! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we
|
||||
//! replace the rvalue/operand by that constant. Otherwise, if there is an SSA local `y`
|
||||
//! associated to this `VnIndex`, and if its definition location strictly dominates the assignment
|
||||
|
@ -91,7 +93,7 @@ use rustc_const_eval::interpret::{
|
|||
ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar,
|
||||
intern_const_alloc_for_constprop,
|
||||
};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::fx::{FxIndexSet, MutableValues};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
|
@ -107,7 +109,7 @@ use rustc_span::def_id::DefId;
|
|||
use smallvec::SmallVec;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::ssa::{AssignedValue, SsaLocals};
|
||||
use crate::ssa::SsaLocals;
|
||||
|
||||
pub(super) struct GVN;
|
||||
|
||||
|
@ -126,31 +128,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
|
|||
let dominators = body.basic_blocks.dominators().clone();
|
||||
|
||||
let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);
|
||||
ssa.for_each_assignment_mut(
|
||||
body.basic_blocks.as_mut_preserves_cfg(),
|
||||
|local, value, location| {
|
||||
let value = match value {
|
||||
// We do not know anything of this assigned value.
|
||||
AssignedValue::Arg | AssignedValue::Terminator => None,
|
||||
// Try to get some insight.
|
||||
AssignedValue::Rvalue(rvalue) => {
|
||||
let value = state.simplify_rvalue(rvalue, location);
|
||||
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
|
||||
// `local` as reusable if we have an exact type match.
|
||||
if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) {
|
||||
return;
|
||||
}
|
||||
value
|
||||
}
|
||||
};
|
||||
// `next_opaque` is `Some`, so `new_opaque` must return `Some`.
|
||||
let value = value.or_else(|| state.new_opaque()).unwrap();
|
||||
state.assign(local, value);
|
||||
},
|
||||
);
|
||||
|
||||
// Stop creating opaques during replacement as it is useless.
|
||||
state.next_opaque = None;
|
||||
for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) {
|
||||
let opaque = state.new_opaque();
|
||||
state.assign(local, opaque);
|
||||
}
|
||||
|
||||
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
|
||||
for bb in reverse_postorder {
|
||||
|
@ -250,14 +232,14 @@ struct VnState<'body, 'tcx> {
|
|||
locals: IndexVec<Local, Option<VnIndex>>,
|
||||
/// Locals that are assigned that value.
|
||||
// This vector does not hold all the values of `VnIndex` that we create.
|
||||
// It stops at the largest value created in the first phase of collecting assignments.
|
||||
rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
|
||||
values: FxIndexSet<Value<'tcx>>,
|
||||
/// Values evaluated as constants if possible.
|
||||
evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
|
||||
/// Counter to generate different values.
|
||||
/// This is an option to stop creating opaques during replacement.
|
||||
next_opaque: Option<usize>,
|
||||
next_opaque: usize,
|
||||
/// Cache the deref values.
|
||||
derefs: Vec<VnIndex>,
|
||||
/// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop.
|
||||
feature_unsized_locals: bool,
|
||||
ssa: &'body SsaLocals,
|
||||
|
@ -289,7 +271,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
rev_locals: IndexVec::with_capacity(num_values),
|
||||
values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
|
||||
evaluated: IndexVec::with_capacity(num_values),
|
||||
next_opaque: Some(1),
|
||||
next_opaque: 1,
|
||||
derefs: Vec::new(),
|
||||
feature_unsized_locals: tcx.features().unsized_locals(),
|
||||
ssa,
|
||||
dominators,
|
||||
|
@ -310,32 +293,31 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
let evaluated = self.eval_to_const(index);
|
||||
let _index = self.evaluated.push(evaluated);
|
||||
debug_assert_eq!(index, _index);
|
||||
// No need to push to `rev_locals` if we finished listing assignments.
|
||||
if self.next_opaque.is_some() {
|
||||
let _index = self.rev_locals.push(SmallVec::new());
|
||||
debug_assert_eq!(index, _index);
|
||||
}
|
||||
let _index = self.rev_locals.push(SmallVec::new());
|
||||
debug_assert_eq!(index, _index);
|
||||
}
|
||||
index
|
||||
}
|
||||
|
||||
fn next_opaque(&mut self) -> usize {
|
||||
let next_opaque = self.next_opaque;
|
||||
self.next_opaque += 1;
|
||||
next_opaque
|
||||
}
|
||||
|
||||
/// Create a new `Value` for which we have no information at all, except that it is distinct
|
||||
/// from all the others.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn new_opaque(&mut self) -> Option<VnIndex> {
|
||||
let next_opaque = self.next_opaque.as_mut()?;
|
||||
let value = Value::Opaque(*next_opaque);
|
||||
*next_opaque += 1;
|
||||
Some(self.insert(value))
|
||||
fn new_opaque(&mut self) -> VnIndex {
|
||||
let value = Value::Opaque(self.next_opaque());
|
||||
self.insert(value)
|
||||
}
|
||||
|
||||
/// Create a new `Value::Address` distinct from all the others.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> Option<VnIndex> {
|
||||
let next_opaque = self.next_opaque.as_mut()?;
|
||||
let value = Value::Address { place, kind, provenance: *next_opaque };
|
||||
*next_opaque += 1;
|
||||
Some(self.insert(value))
|
||||
fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex {
|
||||
let value = Value::Address { place, kind, provenance: self.next_opaque() };
|
||||
self.insert(value)
|
||||
}
|
||||
|
||||
fn get(&self, index: VnIndex) -> &Value<'tcx> {
|
||||
|
@ -345,6 +327,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
/// Record that `local` is assigned `value`. `local` must be SSA.
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn assign(&mut self, local: Local, value: VnIndex) {
|
||||
debug_assert!(self.ssa.is_ssa(local));
|
||||
self.locals[local] = Some(value);
|
||||
|
||||
// Only register the value if its type is `Sized`, as we will emit copies of it.
|
||||
|
@ -355,21 +338,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_constant(&mut self, value: Const<'tcx>) -> Option<VnIndex> {
|
||||
fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex {
|
||||
let disambiguator = if value.is_deterministic() {
|
||||
// The constant is deterministic, no need to disambiguate.
|
||||
0
|
||||
} else {
|
||||
// Multiple mentions of this constant will yield different values,
|
||||
// so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
|
||||
let next_opaque = self.next_opaque.as_mut()?;
|
||||
let disambiguator = *next_opaque;
|
||||
*next_opaque += 1;
|
||||
let disambiguator = self.next_opaque();
|
||||
// `disambiguator: 0` means deterministic.
|
||||
debug_assert_ne!(disambiguator, 0);
|
||||
disambiguator
|
||||
};
|
||||
Some(self.insert(Value::Constant { value, disambiguator }))
|
||||
self.insert(Value::Constant { value, disambiguator })
|
||||
}
|
||||
|
||||
fn insert_bool(&mut self, flag: bool) -> VnIndex {
|
||||
|
@ -390,6 +371,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values))
|
||||
}
|
||||
|
||||
fn insert_deref(&mut self, value: VnIndex) -> VnIndex {
|
||||
let value = self.insert(Value::Projection(value, ProjectionElem::Deref));
|
||||
self.derefs.push(value);
|
||||
value
|
||||
}
|
||||
|
||||
fn invalidate_derefs(&mut self) {
|
||||
for deref in std::mem::take(&mut self.derefs) {
|
||||
let opaque = self.next_opaque();
|
||||
*self.values.get_index_mut2(deref.index()).unwrap() = Value::Opaque(opaque);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
|
||||
use Value::*;
|
||||
|
@ -648,15 +642,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
let proj = match proj {
|
||||
ProjectionElem::Deref => {
|
||||
let ty = place.ty(self.local_decls, self.tcx).ty;
|
||||
// unsound: https://github.com/rust-lang/rust/issues/130853
|
||||
if self.tcx.sess.opts.unstable_opts.unsound_mir_opts
|
||||
&& let Some(Mutability::Not) = ty.ref_mutability()
|
||||
if let Some(Mutability::Not) = ty.ref_mutability()
|
||||
&& let Some(pointee_ty) = ty.builtin_deref(true)
|
||||
&& pointee_ty.is_freeze(self.tcx, self.typing_env())
|
||||
{
|
||||
// An immutable borrow `_x` always points to the same value for the
|
||||
// lifetime of the borrow, so we can merge all instances of `*_x`.
|
||||
ProjectionElem::Deref
|
||||
return Some(self.insert_deref(value));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
@ -830,7 +822,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
location: Location,
|
||||
) -> Option<VnIndex> {
|
||||
match *operand {
|
||||
Operand::Constant(ref constant) => self.insert_constant(constant.const_),
|
||||
Operand::Constant(ref constant) => Some(self.insert_constant(constant.const_)),
|
||||
Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
|
||||
let value = self.simplify_place_value(place, location)?;
|
||||
if let Some(const_) = self.try_as_constant(value) {
|
||||
|
@ -866,11 +858,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location),
|
||||
Rvalue::Ref(_, borrow_kind, ref mut place) => {
|
||||
self.simplify_place_projection(place, location);
|
||||
return self.new_pointer(*place, AddressKind::Ref(borrow_kind));
|
||||
return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind)));
|
||||
}
|
||||
Rvalue::RawPtr(mutbl, ref mut place) => {
|
||||
self.simplify_place_projection(place, location);
|
||||
return self.new_pointer(*place, AddressKind::Address(mutbl));
|
||||
return Some(self.new_pointer(*place, AddressKind::Address(mutbl)));
|
||||
}
|
||||
Rvalue::WrapUnsafeBinder(ref mut op, ty) => {
|
||||
let value = self.simplify_operand(op, location)?;
|
||||
|
@ -1034,7 +1026,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
|
||||
if is_zst {
|
||||
let ty = rvalue.ty(self.local_decls, tcx);
|
||||
return self.insert_constant(Const::zero_sized(ty));
|
||||
return Some(self.insert_constant(Const::zero_sized(ty)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,11 +1055,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let fields: Option<Vec<_>> = field_ops
|
||||
let mut fields: Vec<_> = field_ops
|
||||
.iter_mut()
|
||||
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
|
||||
.map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque()))
|
||||
.collect();
|
||||
let mut fields = fields?;
|
||||
|
||||
if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty {
|
||||
let mut was_updated = false;
|
||||
|
@ -1107,9 +1098,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// unsound: https://github.com/rust-lang/rust/issues/132353
|
||||
if tcx.sess.opts.unstable_opts.unsound_mir_opts
|
||||
&& let AggregateTy::Def(_, _) = ty
|
||||
if let AggregateTy::Def(_, _) = ty
|
||||
&& let Some(value) =
|
||||
self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index)
|
||||
{
|
||||
|
@ -1195,7 +1184,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind()
|
||||
&& let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() =>
|
||||
{
|
||||
return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
|
||||
return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
|
||||
}
|
||||
_ => Value::UnaryOp(op, arg_index),
|
||||
};
|
||||
|
@ -1391,7 +1380,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind {
|
||||
// Each reification of a generic fn may get a different pointer.
|
||||
// Do not try to merge them.
|
||||
return self.new_opaque();
|
||||
return Some(self.new_opaque());
|
||||
}
|
||||
|
||||
let mut was_ever_updated = false;
|
||||
|
@ -1507,7 +1496,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
// Trivial case: we are fetching a statically known length.
|
||||
let place_ty = place.ty(self.local_decls, self.tcx).ty;
|
||||
if let ty::Array(_, len) = place_ty.kind() {
|
||||
return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
|
||||
return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
|
||||
}
|
||||
|
||||
let mut inner = self.simplify_place_value(place, location)?;
|
||||
|
@ -1529,7 +1518,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
&& let Some(to) = to.builtin_deref(true)
|
||||
&& let ty::Slice(..) = to.kind()
|
||||
{
|
||||
return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
|
||||
return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
|
||||
}
|
||||
|
||||
// Fallback: a symbolic `Len`.
|
||||
|
@ -1739,42 +1728,71 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
|
||||
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
self.simplify_place_projection(place, location);
|
||||
if context.is_mutating_use() && !place.projection.is_empty() {
|
||||
// Non-local mutation maybe invalidate deref.
|
||||
self.invalidate_derefs();
|
||||
}
|
||||
self.super_place(place, context, location);
|
||||
}
|
||||
|
||||
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
|
||||
self.simplify_operand(operand, location);
|
||||
self.super_operand(operand, location);
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
|
||||
if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind {
|
||||
self.simplify_place_projection(lhs, location);
|
||||
|
||||
// Do not try to simplify a constant, it's already in canonical shape.
|
||||
if matches!(rvalue, Rvalue::Use(Operand::Constant(_))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value = lhs
|
||||
.as_local()
|
||||
.and_then(|local| self.locals[local])
|
||||
.or_else(|| self.simplify_rvalue(rvalue, location));
|
||||
let Some(value) = value else { return };
|
||||
|
||||
if let Some(const_) = self.try_as_constant(value) {
|
||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
|
||||
} else if let Some(local) = self.try_as_local(value, location)
|
||||
&& *rvalue != Rvalue::Use(Operand::Move(local.into()))
|
||||
let value = self.simplify_rvalue(rvalue, location);
|
||||
let value = if let Some(local) = lhs.as_local()
|
||||
&& self.ssa.is_ssa(local)
|
||||
// FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
|
||||
// `local` as reusable if we have an exact type match.
|
||||
&& self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx)
|
||||
{
|
||||
*rvalue = Rvalue::Use(Operand::Copy(local.into()));
|
||||
self.reused_locals.insert(local);
|
||||
let value = value.unwrap_or_else(|| self.new_opaque());
|
||||
self.assign(local, value);
|
||||
Some(value)
|
||||
} else {
|
||||
value
|
||||
};
|
||||
if let Some(value) = value {
|
||||
if let Some(const_) = self.try_as_constant(value) {
|
||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
|
||||
} else if let Some(local) = self.try_as_local(value, location)
|
||||
&& *rvalue != Rvalue::Use(Operand::Move(local.into()))
|
||||
{
|
||||
*rvalue = Rvalue::Use(Operand::Copy(local.into()));
|
||||
self.reused_locals.insert(local);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
self.super_statement(stmt, location);
|
||||
}
|
||||
|
||||
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
|
||||
if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator {
|
||||
if let Some(local) = destination.as_local()
|
||||
&& self.ssa.is_ssa(local)
|
||||
{
|
||||
let opaque = self.new_opaque();
|
||||
self.assign(local, opaque);
|
||||
}
|
||||
}
|
||||
// Function calls and ASM may invalidate (nested) derefs. We must handle them carefully.
|
||||
// Currently, only preserving derefs for trivial terminators like SwitchInt and Goto.
|
||||
let safe_to_preserve_derefs = matches!(
|
||||
terminator.kind,
|
||||
TerminatorKind::SwitchInt { .. } | TerminatorKind::Goto { .. }
|
||||
);
|
||||
if !safe_to_preserve_derefs {
|
||||
self.invalidate_derefs();
|
||||
}
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
}
|
||||
|
||||
struct StorageRemover<'tcx> {
|
||||
|
|
|
@ -32,12 +32,6 @@ pub(super) struct SsaLocals {
|
|||
borrowed_locals: DenseBitSet<Local>,
|
||||
}
|
||||
|
||||
pub(super) enum AssignedValue<'a, 'tcx> {
|
||||
Arg,
|
||||
Rvalue(&'a mut Rvalue<'tcx>),
|
||||
Terminator,
|
||||
}
|
||||
|
||||
impl SsaLocals {
|
||||
pub(super) fn new<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -152,38 +146,6 @@ impl SsaLocals {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn for_each_assignment_mut<'tcx>(
|
||||
&self,
|
||||
basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
|
||||
mut f: impl FnMut(Local, AssignedValue<'_, 'tcx>, Location),
|
||||
) {
|
||||
for &local in &self.assignment_order {
|
||||
match self.assignments[local] {
|
||||
Set1::One(DefLocation::Argument) => f(
|
||||
local,
|
||||
AssignedValue::Arg,
|
||||
Location { block: START_BLOCK, statement_index: 0 },
|
||||
),
|
||||
Set1::One(DefLocation::Assignment(loc)) => {
|
||||
let bb = &mut basic_blocks[loc.block];
|
||||
// `loc` must point to a direct assignment to `local`.
|
||||
let stmt = &mut bb.statements[loc.statement_index];
|
||||
let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else {
|
||||
bug!()
|
||||
};
|
||||
assert_eq!(target.as_local(), Some(local));
|
||||
f(local, AssignedValue::Rvalue(rvalue), loc)
|
||||
}
|
||||
Set1::One(DefLocation::CallReturn { call, .. }) => {
|
||||
let bb = &mut basic_blocks[call];
|
||||
let loc = Location { block: call, statement_index: bb.statements.len() };
|
||||
f(local, AssignedValue::Terminator, loc)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the equivalence classes for locals, based on copy statements.
|
||||
///
|
||||
/// The returned vector maps each local to the one it copies. In the following case:
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
//@ revisions: DEBUGINFO NODEBUGINFO
|
||||
//@ compile-flags: -Zunsound-mir-opts
|
||||
// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
|
||||
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
|
||||
//@ [DEBUGINFO] compile-flags: -Cdebuginfo=full
|
||||
|
||||
|
|
|
@ -16,12 +16,17 @@ use std::ptr::NonNull;
|
|||
#[no_mangle]
|
||||
pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
|
||||
// CHECK: start:
|
||||
// TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
|
||||
// TWENTY-NEXT: %[[PAYLOAD:.+]] = select i1 %[[IS_SOME]], i32 %1, i32 undef
|
||||
// CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
|
||||
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
|
||||
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %[[PAYLOAD]], 1
|
||||
// CHECK-NEXT: ret { i32, i32 } [[REG2]]
|
||||
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1
|
||||
|
||||
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0
|
||||
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0
|
||||
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1
|
||||
|
||||
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef
|
||||
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
|
||||
// TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1
|
||||
|
||||
// CHECK-NEXT: ret { i32, i32 } [[REG3]]
|
||||
match x {
|
||||
Some(x) => Some(x),
|
||||
None => None,
|
||||
|
@ -90,12 +95,17 @@ pub fn control_flow_nop_traits_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32,
|
|||
#[no_mangle]
|
||||
pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
|
||||
// CHECK: start:
|
||||
// TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1
|
||||
// TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef
|
||||
// CHECK-NEXT: [[REG1:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } poison, i64 %0, 0
|
||||
// NINETEEN-NEXT: [[REG2:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } [[REG1]], i64 %1, 1
|
||||
// TWENTY-NEXT: [[REG2:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } [[REG1]], i64 %[[SEL]], 1
|
||||
// CHECK-NEXT: ret { i64, i64 } [[REG2]]
|
||||
// CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1
|
||||
|
||||
// NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0
|
||||
// NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0
|
||||
// NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1
|
||||
|
||||
// TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef
|
||||
// TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0
|
||||
// TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1
|
||||
|
||||
// CHECK-NEXT: ret { i64, i64 } [[REG3]]
|
||||
match x {
|
||||
Some(x) => Some(x),
|
||||
None => None,
|
||||
|
@ -164,8 +174,8 @@ pub fn control_flow_nop_traits_64(x: ControlFlow<i64, u64>) -> ControlFlow<i64,
|
|||
#[no_mangle]
|
||||
pub fn result_nop_match_128(x: Result<i128, u128>) -> Result<i128, u128> {
|
||||
// CHECK: start:
|
||||
// CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
|
||||
// CHECK-NEXT: store i128
|
||||
// CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
|
||||
// CHECK-NEXT: store i128
|
||||
// CHECK-NEXT: ret void
|
||||
match x {
|
||||
|
@ -189,8 +199,8 @@ pub fn result_nop_traits_128(x: Result<i128, u128>) -> Result<i128, u128> {
|
|||
#[no_mangle]
|
||||
pub fn control_flow_nop_match_128(x: ControlFlow<i128, u128>) -> ControlFlow<i128, u128> {
|
||||
// CHECK: start:
|
||||
// CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
|
||||
// CHECK-NEXT: store i128
|
||||
// CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
|
||||
// CHECK-NEXT: store i128
|
||||
// CHECK-NEXT: ret void
|
||||
match x {
|
||||
|
|
|
@ -59,109 +59,80 @@ Number of file 0 mappings: 1
|
|||
Highest counter ID seen: c0
|
||||
|
||||
Function name: issue_84561::test3
|
||||
Raw bytes (315): 0x[01, 01, 1b, 1d, 21, 25, 29, 21, 25, 2d, 31, 21, 17, 25, 2d, 41, 45, 49, 4d, 51, 55, 33, 51, 49, 4d, 33, 37, 49, 4d, 51, 59, 55, 59, 55, 59, 47, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 63, 79, 71, 75, 79, 7d, 7d, 81, 01, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 0d, 05, 05, 00, 0f, 11, 01, 05, 00, 0f, 15, 01, 09, 01, 0f, 19, 02, 05, 00, 0f, 1d, 01, 05, 00, 0f, 02, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 25, 03, 20, 00, 30, 29, 00, 33, 00, 41, 06, 00, 4b, 00, 5a, 0a, 01, 05, 00, 0f, 2d, 05, 09, 03, 10, 31, 05, 0d, 00, 1b, 0e, 02, 0d, 00, 1c, 12, 04, 09, 02, 0f, 35, 06, 05, 00, 0f, 39, 04, 05, 00, 0f, 3d, 04, 09, 01, 0f, 41, 05, 08, 00, 0f, 45, 01, 09, 00, 13, 1a, 05, 09, 00, 13, 33, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 22, 03, 0d, 00, 1d, 26, 03, 09, 00, 13, 2e, 03, 0d, 00, 1d, 47, 03, 05, 00, 0f, 47, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 42, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 4a, 02, 0d, 00, 13, 63, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 00, 17, 71, 04, 0d, 00, 13, 5a, 02, 0d, 00, 17, 5a, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 5a, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 5e, 03, 09, 00, 19, 79, 02, 05, 00, 0f, 66, 03, 09, 00, 22, 7d, 02, 05, 00, 0f, 6a, 03, 09, 00, 2c, 81, 01, 02, 01, 00, 02]
|
||||
Raw bytes (279): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 09, 05, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 01, 0f, 0d, 02, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 02, 0f, 0d, 06, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 01, 0f, 0d, 05, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 02, 13, 21, 03, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => global file 1
|
||||
Number of expressions: 27
|
||||
- expression 0 operands: lhs = Counter(7), rhs = Counter(8)
|
||||
- expression 1 operands: lhs = Counter(9), rhs = Counter(10)
|
||||
- expression 2 operands: lhs = Counter(8), rhs = Counter(9)
|
||||
- expression 3 operands: lhs = Counter(11), rhs = Counter(12)
|
||||
- expression 4 operands: lhs = Counter(8), rhs = Expression(5, Add)
|
||||
- expression 5 operands: lhs = Counter(9), rhs = Counter(11)
|
||||
- expression 6 operands: lhs = Counter(16), rhs = Counter(17)
|
||||
- expression 7 operands: lhs = Counter(18), rhs = Counter(19)
|
||||
- expression 8 operands: lhs = Counter(20), rhs = Counter(21)
|
||||
- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(20)
|
||||
- expression 10 operands: lhs = Counter(18), rhs = Counter(19)
|
||||
- expression 11 operands: lhs = Expression(12, Add), rhs = Expression(13, Add)
|
||||
- expression 12 operands: lhs = Counter(18), rhs = Counter(19)
|
||||
- expression 13 operands: lhs = Counter(20), rhs = Counter(22)
|
||||
- expression 14 operands: lhs = Counter(21), rhs = Counter(22)
|
||||
- expression 15 operands: lhs = Counter(21), rhs = Counter(22)
|
||||
- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(23)
|
||||
- expression 17 operands: lhs = Counter(21), rhs = Counter(22)
|
||||
- expression 18 operands: lhs = Counter(24), rhs = Counter(25)
|
||||
- expression 19 operands: lhs = Counter(28), rhs = Counter(29)
|
||||
- expression 20 operands: lhs = Counter(26), rhs = Counter(27)
|
||||
- expression 21 operands: lhs = Counter(26), rhs = Counter(27)
|
||||
- expression 22 operands: lhs = Counter(26), rhs = Counter(27)
|
||||
- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(30)
|
||||
- expression 24 operands: lhs = Counter(28), rhs = Counter(29)
|
||||
- expression 25 operands: lhs = Counter(30), rhs = Counter(31)
|
||||
- expression 26 operands: lhs = Counter(31), rhs = Counter(32)
|
||||
Number of expressions: 10
|
||||
- expression 0 operands: lhs = Counter(3), rhs = Counter(4)
|
||||
- expression 1 operands: lhs = Counter(3), rhs = Counter(5)
|
||||
- expression 2 operands: lhs = Counter(3), rhs = Counter(6)
|
||||
- expression 3 operands: lhs = Counter(7), rhs = Counter(8)
|
||||
- expression 4 operands: lhs = Counter(10), rhs = Counter(11)
|
||||
- expression 5 operands: lhs = Counter(9), rhs = Counter(10)
|
||||
- expression 6 operands: lhs = Counter(9), rhs = Counter(10)
|
||||
- expression 7 operands: lhs = Counter(9), rhs = Counter(10)
|
||||
- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12)
|
||||
- expression 9 operands: lhs = Counter(10), rhs = Counter(11)
|
||||
Number of file 0 mappings: 51
|
||||
- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 15)
|
||||
- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 15)
|
||||
- Code(Counter(2)) at (prev + 2, 5) to (start + 4, 15)
|
||||
- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 15)
|
||||
- Code(Counter(4)) at (prev + 1, 5) to (start + 0, 15)
|
||||
- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 15)
|
||||
- Code(Counter(6)) at (prev + 2, 5) to (start + 0, 15)
|
||||
- Code(Counter(7)) at (prev + 1, 5) to (start + 0, 15)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 32) to (start + 0, 48)
|
||||
- Code(Counter(2)) at (prev + 5, 5) to (start + 0, 15)
|
||||
- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15)
|
||||
- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15)
|
||||
- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15)
|
||||
- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
|
||||
- Code(Zero) at (prev + 0, 32) to (start + 0, 48)
|
||||
- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 15)
|
||||
- Code(Zero) at (prev + 3, 32) to (start + 0, 48)
|
||||
- Code(Zero) at (prev + 0, 51) to (start + 0, 65)
|
||||
- Code(Zero) at (prev + 0, 75) to (start + 0, 90)
|
||||
- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
|
||||
- Code(Zero) at (prev + 5, 9) to (start + 3, 16)
|
||||
- Code(Zero) at (prev + 5, 13) to (start + 0, 27)
|
||||
- Code(Zero) at (prev + 2, 13) to (start + 0, 28)
|
||||
- Code(Counter(3)) at (prev + 4, 9) to (start + 2, 15)
|
||||
- Code(Counter(3)) at (prev + 6, 5) to (start + 0, 15)
|
||||
- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15)
|
||||
- Code(Counter(3)) at (prev + 4, 9) to (start + 1, 15)
|
||||
- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15)
|
||||
- Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19)
|
||||
- Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19)
|
||||
= (c3 - c4)
|
||||
- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15)
|
||||
- Code(Counter(5)) at (prev + 1, 9) to (start + 0, 19)
|
||||
- Code(Zero) at (prev + 3, 13) to (start + 0, 29)
|
||||
- Code(Expression(1, Sub)) at (prev + 3, 9) to (start + 0, 19)
|
||||
= (c3 - c5)
|
||||
- Code(Zero) at (prev + 3, 13) to (start + 0, 29)
|
||||
- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 15)
|
||||
- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 19)
|
||||
- Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19)
|
||||
- Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19)
|
||||
= (c3 - c6)
|
||||
- Code(Counter(7)) at (prev + 4, 5) to (start + 2, 19)
|
||||
- Code(Counter(8)) at (prev + 3, 13) to (start + 0, 19)
|
||||
- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19)
|
||||
= (c7 - c8)
|
||||
- Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15)
|
||||
- Code(Counter(9)) at (prev + 3, 32) to (start + 0, 48)
|
||||
- Code(Counter(10)) at (prev + 0, 51) to (start + 0, 65)
|
||||
- Code(Expression(1, Sub)) at (prev + 0, 75) to (start + 0, 90)
|
||||
- Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15)
|
||||
= (c10 + c11)
|
||||
- Code(Counter(9)) at (prev + 1, 12) to (start + 0, 19)
|
||||
- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 23)
|
||||
- Code(Counter(10)) at (prev + 4, 13) to (start + 0, 19)
|
||||
- Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 23)
|
||||
= (c9 - c10)
|
||||
- Code(Expression(7, Sub)) at (prev + 1, 20) to (start + 0, 27)
|
||||
= (c9 - c10)
|
||||
- Code(Expression(2, Sub)) at (prev + 1, 5) to (start + 0, 15)
|
||||
= (c8 - c9)
|
||||
- Code(Counter(11)) at (prev + 5, 9) to (start + 3, 16)
|
||||
- Code(Counter(12)) at (prev + 5, 13) to (start + 0, 27)
|
||||
- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 28)
|
||||
= (c11 - c12)
|
||||
- Code(Expression(4, Sub)) at (prev + 4, 9) to (start + 2, 15)
|
||||
= (c8 - (c9 + c11))
|
||||
- Code(Counter(13)) at (prev + 6, 5) to (start + 0, 15)
|
||||
- Code(Counter(14)) at (prev + 4, 5) to (start + 0, 15)
|
||||
- Code(Counter(15)) at (prev + 4, 9) to (start + 1, 15)
|
||||
- Code(Counter(16)) at (prev + 5, 8) to (start + 0, 15)
|
||||
- Code(Counter(17)) at (prev + 1, 9) to (start + 0, 19)
|
||||
- Code(Expression(6, Sub)) at (prev + 5, 9) to (start + 0, 19)
|
||||
= (c16 - c17)
|
||||
- Code(Expression(12, Add)) at (prev + 5, 8) to (start + 0, 15)
|
||||
= (c18 + c19)
|
||||
- Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19)
|
||||
- Code(Expression(8, Sub)) at (prev + 3, 13) to (start + 0, 29)
|
||||
= (c20 - c21)
|
||||
- Code(Expression(9, Sub)) at (prev + 3, 9) to (start + 0, 19)
|
||||
= ((c18 + c19) - c20)
|
||||
- Code(Expression(11, Sub)) at (prev + 3, 13) to (start + 0, 29)
|
||||
= ((c18 + c19) - (c20 + c22))
|
||||
- Code(Expression(17, Add)) at (prev + 3, 5) to (start + 0, 15)
|
||||
= (c21 + c22)
|
||||
- Code(Expression(17, Add)) at (prev + 1, 12) to (start + 0, 19)
|
||||
= (c21 + c22)
|
||||
- Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19)
|
||||
- Code(Expression(16, Sub)) at (prev + 2, 13) to (start + 0, 19)
|
||||
= ((c21 + c22) - c23)
|
||||
- Code(Counter(24)) at (prev + 4, 5) to (start + 2, 19)
|
||||
- Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19)
|
||||
- Code(Expression(18, Sub)) at (prev + 2, 13) to (start + 0, 19)
|
||||
= (c24 - c25)
|
||||
- Code(Expression(24, Add)) at (prev + 3, 5) to (start + 0, 15)
|
||||
= (c28 + c29)
|
||||
- Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19)
|
||||
- Code(Counter(27)) at (prev + 1, 13) to (start + 0, 23)
|
||||
- Code(Counter(28)) at (prev + 4, 13) to (start + 0, 19)
|
||||
- Code(Expression(22, Sub)) at (prev + 2, 13) to (start + 0, 23)
|
||||
= (c26 - c27)
|
||||
- Code(Expression(22, Sub)) at (prev + 1, 20) to (start + 0, 27)
|
||||
= (c26 - c27)
|
||||
- Code(Zero) at (prev + 1, 21) to (start + 0, 27)
|
||||
- Code(Expression(22, Sub)) at (prev + 2, 21) to (start + 0, 27)
|
||||
= (c26 - c27)
|
||||
- Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19)
|
||||
- Code(Expression(23, Sub)) at (prev + 3, 9) to (start + 0, 25)
|
||||
= ((c28 + c29) - c30)
|
||||
- Code(Counter(30)) at (prev + 2, 5) to (start + 0, 15)
|
||||
- Code(Expression(25, Sub)) at (prev + 3, 9) to (start + 0, 34)
|
||||
= (c30 - c31)
|
||||
- Code(Counter(31)) at (prev + 2, 5) to (start + 0, 15)
|
||||
- Code(Expression(26, Sub)) at (prev + 3, 9) to (start + 0, 44)
|
||||
= (c31 - c32)
|
||||
- Code(Counter(32)) at (prev + 2, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c32
|
||||
- Code(Expression(7, Sub)) at (prev + 2, 21) to (start + 0, 27)
|
||||
= (c9 - c10)
|
||||
- Code(Counter(11)) at (prev + 4, 13) to (start + 0, 19)
|
||||
- Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 25)
|
||||
= ((c10 + c11) - c12)
|
||||
- Code(Counter(12)) at (prev + 2, 5) to (start + 0, 15)
|
||||
- Code(Counter(12)) at (prev + 3, 9) to (start + 0, 34)
|
||||
- Code(Zero) at (prev + 2, 5) to (start + 0, 15)
|
||||
- Code(Zero) at (prev + 3, 9) to (start + 0, 44)
|
||||
- Code(Zero) at (prev + 2, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c12
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = const <bool as NeedsDrop>::NEEDS;
|
||||
- _1 = const <bool as NeedsDrop>::NEEDS;
|
||||
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
|
||||
+ _1 = const false;
|
||||
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = const <bool as NeedsDrop>::NEEDS;
|
||||
- _1 = const <bool as NeedsDrop>::NEEDS;
|
||||
- switchInt(move _1) -> [0: bb2, otherwise: bb1];
|
||||
+ _1 = const false;
|
||||
+ switchInt(const false) -> [0: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
|
|
|
@ -14,19 +14,23 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
- StorageLive(_2);
|
||||
- StorageLive(_3);
|
||||
+ nop;
|
||||
+ nop;
|
||||
_3 = const {ALLOC0: &u8};
|
||||
_2 = copy (*_3);
|
||||
- _2 = copy (*_3);
|
||||
+ _2 = const 2_u8;
|
||||
StorageLive(_4);
|
||||
StorageLive(_5);
|
||||
_5 = const {ALLOC0: &u8};
|
||||
- _4 = copy (*_5);
|
||||
+ _4 = copy (*_3);
|
||||
_1 = Add(move _2, move _4);
|
||||
- _1 = Add(move _2, move _4);
|
||||
+ _4 = const 2_u8;
|
||||
+ _1 = const 4_u8;
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
StorageDead(_5);
|
||||
- StorageDead(_3);
|
||||
+ nop;
|
||||
|
|
|
@ -6,7 +6,6 @@ static FOO: u8 = 2;
|
|||
fn main() {
|
||||
// CHECK-LABEL: fn main(
|
||||
// CHECK: debug x => [[x:_.*]];
|
||||
// Disabled due to <https://github.com/rust-lang/rust/issues/130853>
|
||||
// COM: CHECK: [[x]] = const 4_u8;
|
||||
// CHECK: [[x]] = const 4_u8;
|
||||
let x = FOO + FOO;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
StorageLive(_2);
|
||||
_4 = const main::promoted[0];
|
||||
_2 = &(*_4);
|
||||
_1 = copy (*_2);
|
||||
- _1 = copy (*_2);
|
||||
+ _1 = const 4_i32;
|
||||
StorageDead(_2);
|
||||
_0 = const ();
|
||||
StorageDead(_1);
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
StorageLive(_2);
|
||||
_4 = const main::promoted[0];
|
||||
_2 = &((*_4).1: i32);
|
||||
_1 = copy (*_2);
|
||||
- _1 = copy (*_2);
|
||||
+ _1 = const 5_i32;
|
||||
StorageDead(_2);
|
||||
_0 = const ();
|
||||
StorageDead(_1);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
fn main() {
|
||||
// CHECK-LABEL: fn main(
|
||||
// CHECK: debug a => [[a:_.*]];
|
||||
// Disabled due to <https://github.com/rust-lang/rust/issues/130853>
|
||||
// COM: CHECK: [[a]] = const 5_i32;
|
||||
// CHECK: [[a]] = const 5_i32;
|
||||
let a = *(&(4, 5).1);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
+ _1 = const 2_u32;
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
+ _1 = const 2_u32;
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
+ _1 = const 2_u32;
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
bb1: {
|
||||
- _1 = copy (*_2)[_6];
|
||||
+ _1 = copy (*_2)[1 of 2];
|
||||
+ _1 = const 2_u32;
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
|
|
|
@ -8,8 +8,7 @@ fn main() {
|
|||
// CHECK-LABEL: fn main(
|
||||
// CHECK: debug a => [[a:_.*]];
|
||||
// CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast));
|
||||
// Disabled due to <https://github.com/rust-lang/rust/issues/130853>
|
||||
// COM: CHECK: assert(const true,
|
||||
// COM: CHECK: [[a]] = const 2_u32;
|
||||
// CHECK: assert(const true,
|
||||
// CHECK: [[a]] = const 2_u32;
|
||||
let a = (&[1u32, 2, 3] as &[u32])[1];
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
- _2 = ();
|
||||
- _1 = Union32 { value: move _2 };
|
||||
+ _2 = const ();
|
||||
_1 = Union32 { value: move _2 };
|
||||
+ _1 = Union32 { value: const () };
|
||||
StorageDead(_2);
|
||||
_0 = move _1 as u32 (Transmute);
|
||||
StorageDead(_1);
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
- _2 = ();
|
||||
- _1 = Union32 { value: move _2 };
|
||||
+ _2 = const ();
|
||||
_1 = Union32 { value: move _2 };
|
||||
+ _1 = Union32 { value: const () };
|
||||
StorageDead(_2);
|
||||
_0 = move _1 as u32 (Transmute);
|
||||
StorageDead(_1);
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
let mut _0: ();
|
||||
let _1: main::Un;
|
||||
let mut _2: u32;
|
||||
let mut _3: u32;
|
||||
scope 1 {
|
||||
debug un => _1;
|
||||
scope 3 (inlined std::mem::drop::<u32>) {
|
||||
debug _x => _3;
|
||||
debug _x => _2;
|
||||
}
|
||||
}
|
||||
scope 2 (inlined val) {
|
||||
|
@ -17,13 +16,10 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
nop;
|
||||
_1 = Un { us: const 1_u32 };
|
||||
StorageLive(_2);
|
||||
_2 = copy (_1.0: u32);
|
||||
StorageDead(_2);
|
||||
StorageLive(_3);
|
||||
_3 = copy (_1.0: u32);
|
||||
StorageDead(_3);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
let mut _0: ();
|
||||
let _1: main::Un;
|
||||
let mut _2: u32;
|
||||
let mut _3: u32;
|
||||
scope 1 {
|
||||
debug un => _1;
|
||||
scope 3 (inlined std::mem::drop::<u32>) {
|
||||
debug _x => _3;
|
||||
debug _x => _2;
|
||||
}
|
||||
}
|
||||
scope 2 (inlined val) {
|
||||
|
@ -17,13 +16,10 @@
|
|||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
nop;
|
||||
_1 = Un { us: const 1_u32 };
|
||||
StorageLive(_2);
|
||||
_2 = copy (_1.0: u32);
|
||||
StorageDead(_2);
|
||||
StorageLive(_3);
|
||||
_3 = copy (_1.0: u32);
|
||||
StorageDead(_3);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
}
|
||||
|
||||
bb2: {
|
||||
_0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind unreachable];
|
||||
- _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind unreachable];
|
||||
+ _0 = opaque::<T>(copy _1) -> [return: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
}
|
||||
|
||||
bb2: {
|
||||
_0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind continue];
|
||||
- _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind continue];
|
||||
+ _0 = opaque::<T>(copy _1) -> [return: bb3, unwind continue];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
let mut _3: fn(u8) -> u8;
|
||||
let _5: ();
|
||||
let mut _6: fn(u8) -> u8;
|
||||
let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
let _10: ();
|
||||
let mut _11: fn();
|
||||
let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
let _14: ();
|
||||
let mut _15: fn();
|
||||
scope 1 {
|
||||
|
@ -19,7 +19,7 @@
|
|||
let _4: fn(u8) -> u8;
|
||||
scope 2 {
|
||||
debug g => _4;
|
||||
let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
scope 3 {
|
||||
debug closure => _7;
|
||||
let _8: fn();
|
||||
|
@ -62,16 +62,16 @@
|
|||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
- StorageLive(_7);
|
||||
- _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
- _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
- StorageLive(_8);
|
||||
+ nop;
|
||||
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
+ nop;
|
||||
StorageLive(_9);
|
||||
- _9 = copy _7;
|
||||
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
StorageDead(_9);
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
|
@ -88,8 +88,8 @@
|
|||
StorageLive(_13);
|
||||
- _13 = copy _7;
|
||||
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
StorageDead(_13);
|
||||
StorageLive(_14);
|
||||
StorageLive(_15);
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
let mut _3: fn(u8) -> u8;
|
||||
let _5: ();
|
||||
let mut _6: fn(u8) -> u8;
|
||||
let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
let _10: ();
|
||||
let mut _11: fn();
|
||||
let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
let _14: ();
|
||||
let mut _15: fn();
|
||||
scope 1 {
|
||||
|
@ -19,7 +19,7 @@
|
|||
let _4: fn(u8) -> u8;
|
||||
scope 2 {
|
||||
debug g => _4;
|
||||
let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
scope 3 {
|
||||
debug closure => _7;
|
||||
let _8: fn();
|
||||
|
@ -62,16 +62,16 @@
|
|||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
- StorageLive(_7);
|
||||
- _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
- _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
- StorageLive(_8);
|
||||
+ nop;
|
||||
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
+ nop;
|
||||
StorageLive(_9);
|
||||
- _9 = copy _7;
|
||||
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
StorageDead(_9);
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
|
@ -88,8 +88,8 @@
|
|||
StorageLive(_13);
|
||||
- _13 = copy _7;
|
||||
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
|
||||
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
|
||||
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
|
||||
StorageDead(_13);
|
||||
StorageLive(_14);
|
||||
StorageLive(_15);
|
||||
|
|
|
@ -100,17 +100,18 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
|
|||
opaque((x * y) - y);
|
||||
|
||||
// We cannot substitute through an immutable reference.
|
||||
// (Disabled due to <https://github.com/rust-lang/rust/issues/130853>)
|
||||
// CHECK: [[ref:_.*]] = &_3;
|
||||
// CHECK: [[deref:_.*]] = copy (*[[ref]]);
|
||||
// COM: CHECK: [[addref:_.*]] = Add(copy [[deref]], copy _1);
|
||||
// COM: CHECK: opaque::<u64>(copy [[addref]])
|
||||
// COM: CHECK: opaque::<u64>(copy [[addref]])
|
||||
// CHECK: [[addref:_.*]] = Add(move [[deref]], copy _1);
|
||||
// CHECK: opaque::<u64>(move [[addref]])
|
||||
// CHECK: [[deref2:_.*]] = copy (*[[ref]]);
|
||||
// CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1);
|
||||
// CHECK: opaque::<u64>(move [[addref2]])
|
||||
let a = &z;
|
||||
opaque(*a + x);
|
||||
opaque(*a + x);
|
||||
|
||||
// And certainly not through a mutable reference or a pointer.
|
||||
// But not through a mutable reference or a pointer.
|
||||
// CHECK: [[mut:_.*]] = &mut _3;
|
||||
// CHECK: [[addmut:_.*]] = Add(
|
||||
// CHECK: opaque::<u64>(move [[addmut]])
|
||||
|
@ -142,9 +143,11 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
|
|||
// Important: `e` is not `a`!
|
||||
// CHECK: [[ref2:_.*]] = &_3;
|
||||
// CHECK: [[deref2:_.*]] = copy (*[[ref2]]);
|
||||
// COM: CHECK: [[addref2:_.*]] = Add(copy [[deref2]], copy _1);
|
||||
// COM: CHECK: opaque::<u64>(copy [[addref2]])
|
||||
// COM: CHECK: opaque::<u64>(copy [[addref2]])
|
||||
// CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1);
|
||||
// CHECK: opaque::<u64>(move [[addref2]])
|
||||
// CHECK: [[deref3:_.*]] = copy (*[[ref2]]);
|
||||
// CHECK: [[addref3:_.*]] = Add(move [[deref3]], copy _1);
|
||||
// CHECK: opaque::<u64>(move [[addref3]])
|
||||
let e = &z;
|
||||
opaque(*e + x);
|
||||
opaque(*e + x);
|
||||
|
@ -499,8 +502,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
|
|||
// Do not reuse dereferences of `&Freeze`.
|
||||
// CHECK: [[ref:_.*]] = &(*_1);
|
||||
// CHECK: [[st7:_.*]] = copy (*[[ref]]);
|
||||
// COM: CHECK: opaque::<u32>(copy [[st7]])
|
||||
// COM: CHECK: opaque::<u32>(copy [[st7]])
|
||||
// CHECK: opaque::<u32>(move [[st7]])
|
||||
// CHECK: [[st8:_.*]] = copy (*[[ref]]);
|
||||
// CHECK: opaque::<u32>(move [[st8]])
|
||||
let z = &*t;
|
||||
opaque(*z);
|
||||
opaque(*z);
|
||||
|
@ -519,8 +523,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
|
|||
|
||||
// `*s` is not Copy, but `(*s).0` is, but we still cannot reuse.
|
||||
// CHECK: [[st10:_.*]] = copy ((*_3).0: u32);
|
||||
// COM: CHECK: opaque::<u32>(copy [[st10]])
|
||||
// COM: CHECK: opaque::<u32>(copy [[st10]])
|
||||
// CHECK: opaque::<u32>(move [[st10]])
|
||||
// CHECK: [[st11:_.*]] = copy ((*_3).0: u32);
|
||||
// CHECK: opaque::<u32>(move [[st11]])
|
||||
opaque(s.0);
|
||||
opaque(s.0);
|
||||
}
|
||||
|
@ -737,7 +742,7 @@ fn borrowed<T: Copy + Freeze>(x: T) {
|
|||
// CHECK: bb1: {
|
||||
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
|
||||
// CHECK: bb2: {
|
||||
// COM: CHECK-NEXT: _0 = opaque::<T>(copy _1)
|
||||
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
|
||||
mir! {
|
||||
{
|
||||
let a = x;
|
||||
|
|
|
@ -111,8 +111,9 @@
|
|||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- StorageLive(_9);
|
||||
- StorageLive(_10);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
_11 = &(*_1);
|
||||
_10 = core::str::<impl str>::as_ptr(move _11) -> [return: bb3, unwind unreachable];
|
||||
|
@ -122,8 +123,9 @@
|
|||
StorageDead(_11);
|
||||
_9 = &_10;
|
||||
- StorageLive(_12);
|
||||
- StorageLive(_13);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_13);
|
||||
StorageLive(_14);
|
||||
- _14 = &(*_4);
|
||||
+ _14 = &(*_1);
|
||||
|
@ -148,11 +150,12 @@
|
|||
StorageLive(_17);
|
||||
StorageLive(_18);
|
||||
- _18 = copy (*_15);
|
||||
+ _18 = copy (*_9);
|
||||
+ _18 = copy _10;
|
||||
StorageLive(_19);
|
||||
- _19 = copy (*_16);
|
||||
+ _19 = copy (*_12);
|
||||
_17 = Eq(move _18, move _19);
|
||||
- _17 = Eq(move _18, move _19);
|
||||
+ _19 = copy _13;
|
||||
+ _17 = Eq(copy _10, copy _13);
|
||||
switchInt(move _17) -> [0: bb6, otherwise: bb5];
|
||||
}
|
||||
|
||||
|
@ -163,8 +166,10 @@
|
|||
StorageDead(_17);
|
||||
StorageDead(_16);
|
||||
StorageDead(_15);
|
||||
StorageDead(_13);
|
||||
StorageDead(_10);
|
||||
- StorageDead(_13);
|
||||
- StorageDead(_10);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
- StorageLive(_29);
|
||||
|
@ -213,8 +218,9 @@
|
|||
StorageLive(_33);
|
||||
StorageLive(_34);
|
||||
- StorageLive(_35);
|
||||
- StorageLive(_36);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_36);
|
||||
StorageLive(_37);
|
||||
_37 = &(*_1);
|
||||
_36 = core::str::<impl str>::as_ptr(move _37) -> [return: bb8, unwind unreachable];
|
||||
|
@ -224,8 +230,9 @@
|
|||
StorageDead(_37);
|
||||
_35 = &_36;
|
||||
- StorageLive(_38);
|
||||
- StorageLive(_39);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_39);
|
||||
StorageLive(_40);
|
||||
_40 = &(*_29);
|
||||
_39 = core::slice::<impl [u8]>::as_ptr(move _40) -> [return: bb9, unwind unreachable];
|
||||
|
@ -249,11 +256,12 @@
|
|||
StorageLive(_43);
|
||||
StorageLive(_44);
|
||||
- _44 = copy (*_41);
|
||||
+ _44 = copy (*_35);
|
||||
+ _44 = copy _36;
|
||||
StorageLive(_45);
|
||||
- _45 = copy (*_42);
|
||||
+ _45 = copy (*_38);
|
||||
_43 = Eq(move _44, move _45);
|
||||
- _43 = Eq(move _44, move _45);
|
||||
+ _45 = copy _39;
|
||||
+ _43 = Eq(copy _36, copy _39);
|
||||
switchInt(move _43) -> [0: bb11, otherwise: bb10];
|
||||
}
|
||||
|
||||
|
@ -264,8 +272,10 @@
|
|||
StorageDead(_43);
|
||||
StorageDead(_42);
|
||||
StorageDead(_41);
|
||||
StorageDead(_39);
|
||||
StorageDead(_36);
|
||||
- StorageDead(_39);
|
||||
- StorageDead(_36);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageDead(_34);
|
||||
StorageDead(_33);
|
||||
_0 = const ();
|
||||
|
|
|
@ -111,8 +111,9 @@
|
|||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
- StorageLive(_9);
|
||||
- StorageLive(_10);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
_11 = &(*_1);
|
||||
_10 = core::str::<impl str>::as_ptr(move _11) -> [return: bb3, unwind continue];
|
||||
|
@ -122,8 +123,9 @@
|
|||
StorageDead(_11);
|
||||
_9 = &_10;
|
||||
- StorageLive(_12);
|
||||
- StorageLive(_13);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_13);
|
||||
StorageLive(_14);
|
||||
- _14 = &(*_4);
|
||||
+ _14 = &(*_1);
|
||||
|
@ -148,11 +150,12 @@
|
|||
StorageLive(_17);
|
||||
StorageLive(_18);
|
||||
- _18 = copy (*_15);
|
||||
+ _18 = copy (*_9);
|
||||
+ _18 = copy _10;
|
||||
StorageLive(_19);
|
||||
- _19 = copy (*_16);
|
||||
+ _19 = copy (*_12);
|
||||
_17 = Eq(move _18, move _19);
|
||||
- _17 = Eq(move _18, move _19);
|
||||
+ _19 = copy _13;
|
||||
+ _17 = Eq(copy _10, copy _13);
|
||||
switchInt(move _17) -> [0: bb6, otherwise: bb5];
|
||||
}
|
||||
|
||||
|
@ -163,8 +166,10 @@
|
|||
StorageDead(_17);
|
||||
StorageDead(_16);
|
||||
StorageDead(_15);
|
||||
StorageDead(_13);
|
||||
StorageDead(_10);
|
||||
- StorageDead(_13);
|
||||
- StorageDead(_10);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
- StorageLive(_29);
|
||||
|
@ -213,8 +218,9 @@
|
|||
StorageLive(_33);
|
||||
StorageLive(_34);
|
||||
- StorageLive(_35);
|
||||
- StorageLive(_36);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_36);
|
||||
StorageLive(_37);
|
||||
_37 = &(*_1);
|
||||
_36 = core::str::<impl str>::as_ptr(move _37) -> [return: bb8, unwind continue];
|
||||
|
@ -224,8 +230,9 @@
|
|||
StorageDead(_37);
|
||||
_35 = &_36;
|
||||
- StorageLive(_38);
|
||||
- StorageLive(_39);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageLive(_39);
|
||||
StorageLive(_40);
|
||||
_40 = &(*_29);
|
||||
_39 = core::slice::<impl [u8]>::as_ptr(move _40) -> [return: bb9, unwind continue];
|
||||
|
@ -249,11 +256,12 @@
|
|||
StorageLive(_43);
|
||||
StorageLive(_44);
|
||||
- _44 = copy (*_41);
|
||||
+ _44 = copy (*_35);
|
||||
+ _44 = copy _36;
|
||||
StorageLive(_45);
|
||||
- _45 = copy (*_42);
|
||||
+ _45 = copy (*_38);
|
||||
_43 = Eq(move _44, move _45);
|
||||
- _43 = Eq(move _44, move _45);
|
||||
+ _45 = copy _39;
|
||||
+ _43 = Eq(copy _36, copy _39);
|
||||
switchInt(move _43) -> [0: bb11, otherwise: bb10];
|
||||
}
|
||||
|
||||
|
@ -264,8 +272,10 @@
|
|||
StorageDead(_43);
|
||||
StorageDead(_42);
|
||||
StorageDead(_41);
|
||||
StorageDead(_39);
|
||||
StorageDead(_36);
|
||||
- StorageDead(_39);
|
||||
- StorageDead(_36);
|
||||
+ nop;
|
||||
+ nop;
|
||||
StorageDead(_34);
|
||||
StorageDead(_33);
|
||||
_0 = const ();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
//@ compile-flags: -Zunsound-mir-opts
|
||||
// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
|
||||
//@ test-mir-pass: GVN
|
||||
//@ compile-flags: -Zmir-enable-passes=+InstSimplify-before-inline
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- // MIR for `<impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone` before GVN
|
||||
+ // MIR for `<impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone` after GVN
|
||||
- // MIR for `<impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone` before GVN
|
||||
+ // MIR for `<impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone` after GVN
|
||||
|
||||
fn <impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone(_1: &AllCopy) -> AllCopy {
|
||||
fn <impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone(_1: &AllCopy) -> AllCopy {
|
||||
debug self => _1;
|
||||
let mut _0: AllCopy;
|
||||
let mut _2: i32;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
//@ compile-flags: -Zunsound-mir-opts
|
||||
// FIXME: see <https://github.com/rust-lang/rust/issues/132353.
|
||||
//@ test-mir-pass: GVN
|
||||
//@ compile-flags: -Cpanic=abort
|
||||
|
||||
|
|
|
@ -17,15 +17,16 @@
|
|||
StorageLive(_3);
|
||||
_5 = const f::promoted[0];
|
||||
_3 = &(*_5);
|
||||
_2 = copy ((*_3).1: E);
|
||||
- StorageLive(_1);
|
||||
+ nop;
|
||||
_1 = copy ((_2 as A).1: u32);
|
||||
- _2 = copy ((*_3).1: E);
|
||||
+ _2 = const Scalar(0x00000000): E;
|
||||
StorageLive(_1);
|
||||
- _1 = copy ((_2 as A).1: u32);
|
||||
+ _1 = const 0_u32;
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
_0 = copy _1;
|
||||
- StorageDead(_1);
|
||||
+ nop;
|
||||
- _0 = copy _1;
|
||||
+ _0 = const 0_u32;
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,16 @@
|
|||
StorageLive(_3);
|
||||
_5 = const f::promoted[0];
|
||||
_3 = &(*_5);
|
||||
_2 = copy ((*_3).1: E);
|
||||
- StorageLive(_1);
|
||||
+ nop;
|
||||
_1 = copy ((_2 as A).1: u32);
|
||||
- _2 = copy ((*_3).1: E);
|
||||
+ _2 = const Scalar(0x00000000): E;
|
||||
StorageLive(_1);
|
||||
- _1 = copy ((_2 as A).1: u32);
|
||||
+ _1 = const 0_u32;
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
_0 = copy _1;
|
||||
- StorageDead(_1);
|
||||
+ nop;
|
||||
- _0 = copy _1;
|
||||
+ _0 = const 0_u32;
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
//@ compile-flags: -Zunsound-mir-opts
|
||||
// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
|
||||
//@ compile-flags: -Cdebuginfo=full
|
||||
|
||||
// Check if we have transformed the nested clone to the copy in the complete pipeline.
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//! Regression test for <https://github.com/rust-lang/rust/issues/130853>
|
||||
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
||||
|
||||
fn src(x: &&u8) -> bool {
|
||||
|
|
|
@ -3,13 +3,9 @@
|
|||
fn <impl at $DIR/no_inlined_clone.rs:9:10: 9:15>::clone(_1: &Foo) -> Foo {
|
||||
debug self => _1;
|
||||
let mut _0: Foo;
|
||||
let mut _2: i32;
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
_2 = copy ((*_1).0: i32);
|
||||
_0 = Foo { a: move _2 };
|
||||
StorageDead(_2);
|
||||
_0 = copy (*_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,70 +4,65 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
|
|||
let mut _0: bool;
|
||||
let mut _3: &(usize, usize, usize, usize);
|
||||
let _4: &usize;
|
||||
let mut _5: &(usize, usize, usize, usize);
|
||||
let _5: &usize;
|
||||
let _6: &usize;
|
||||
let mut _7: &(usize, usize, usize, usize);
|
||||
let _8: &usize;
|
||||
let mut _9: &(usize, usize, usize, usize);
|
||||
let _10: &usize;
|
||||
let mut _11: &&usize;
|
||||
let _12: &usize;
|
||||
let mut _13: &&usize;
|
||||
let mut _16: bool;
|
||||
let mut _17: &&usize;
|
||||
let _18: &usize;
|
||||
let mut _19: &&usize;
|
||||
let mut _22: bool;
|
||||
let mut _23: &&usize;
|
||||
let _24: &usize;
|
||||
let mut _25: &&usize;
|
||||
let mut _28: bool;
|
||||
let mut _29: &&usize;
|
||||
let _30: &usize;
|
||||
let mut _31: &&usize;
|
||||
let _7: &usize;
|
||||
let mut _8: &&usize;
|
||||
let _9: &usize;
|
||||
let mut _10: &&usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: &&usize;
|
||||
let _15: &usize;
|
||||
let mut _16: &&usize;
|
||||
let mut _19: bool;
|
||||
let mut _20: &&usize;
|
||||
let _21: &usize;
|
||||
let mut _22: &&usize;
|
||||
let mut _23: bool;
|
||||
let mut _24: &&usize;
|
||||
let _25: &usize;
|
||||
let mut _26: &&usize;
|
||||
scope 1 {
|
||||
debug a => _4;
|
||||
debug b => _6;
|
||||
debug c => _8;
|
||||
debug d => _10;
|
||||
debug b => _5;
|
||||
debug c => _6;
|
||||
debug d => _7;
|
||||
scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
|
||||
debug self => _11;
|
||||
debug other => _13;
|
||||
debug self => _8;
|
||||
debug other => _10;
|
||||
scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
|
||||
debug self => _4;
|
||||
debug other => _8;
|
||||
let mut _14: usize;
|
||||
let mut _15: usize;
|
||||
debug other => _6;
|
||||
let mut _11: usize;
|
||||
let mut _12: usize;
|
||||
}
|
||||
}
|
||||
scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
|
||||
debug self => _17;
|
||||
debug other => _19;
|
||||
debug self => _14;
|
||||
debug other => _16;
|
||||
scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
|
||||
debug self => _10;
|
||||
debug other => _6;
|
||||
let mut _20: usize;
|
||||
let mut _21: usize;
|
||||
debug self => _7;
|
||||
debug other => _5;
|
||||
let mut _17: usize;
|
||||
let mut _18: usize;
|
||||
}
|
||||
}
|
||||
scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
|
||||
debug self => _23;
|
||||
debug other => _25;
|
||||
debug self => _20;
|
||||
debug other => _22;
|
||||
scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
|
||||
debug self => _8;
|
||||
debug self => _6;
|
||||
debug other => _4;
|
||||
let mut _26: usize;
|
||||
let mut _27: usize;
|
||||
}
|
||||
}
|
||||
scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
|
||||
debug self => _29;
|
||||
debug other => _31;
|
||||
debug self => _24;
|
||||
debug other => _26;
|
||||
scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
|
||||
debug self => _6;
|
||||
debug other => _10;
|
||||
let mut _32: usize;
|
||||
let mut _33: usize;
|
||||
debug self => _5;
|
||||
debug other => _7;
|
||||
let mut _27: usize;
|
||||
let mut _28: usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,129 +70,116 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
|
|||
bb0: {
|
||||
_3 = copy (*_2);
|
||||
_4 = &((*_3).0: usize);
|
||||
_5 = copy (*_2);
|
||||
_6 = &((*_5).1: usize);
|
||||
_7 = copy (*_2);
|
||||
_8 = &((*_7).2: usize);
|
||||
_9 = copy (*_2);
|
||||
_10 = &((*_9).3: usize);
|
||||
StorageLive(_16);
|
||||
StorageLive(_11);
|
||||
_11 = &_4;
|
||||
_5 = &((*_3).1: usize);
|
||||
_6 = &((*_3).2: usize);
|
||||
_7 = &((*_3).3: usize);
|
||||
StorageLive(_13);
|
||||
StorageLive(_12);
|
||||
_12 = copy _8;
|
||||
_13 = &_12;
|
||||
StorageLive(_14);
|
||||
_14 = copy ((*_3).0: usize);
|
||||
StorageLive(_15);
|
||||
_15 = copy ((*_7).2: usize);
|
||||
_16 = Le(move _14, move _15);
|
||||
StorageDead(_15);
|
||||
StorageDead(_14);
|
||||
switchInt(move _16) -> [0: bb1, otherwise: bb2];
|
||||
StorageLive(_8);
|
||||
_8 = &_4;
|
||||
StorageLive(_10);
|
||||
StorageLive(_9);
|
||||
_9 = copy _6;
|
||||
_10 = &_9;
|
||||
_11 = copy ((*_3).0: usize);
|
||||
_12 = copy ((*_3).2: usize);
|
||||
_13 = Le(copy _11, copy _12);
|
||||
switchInt(move _13) -> [0: bb1, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_12);
|
||||
StorageDead(_13);
|
||||
StorageDead(_11);
|
||||
StorageDead(_9);
|
||||
StorageDead(_10);
|
||||
StorageDead(_8);
|
||||
goto -> bb4;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_12);
|
||||
StorageDead(_13);
|
||||
StorageDead(_11);
|
||||
StorageLive(_22);
|
||||
StorageLive(_17);
|
||||
_17 = &_10;
|
||||
StorageDead(_9);
|
||||
StorageDead(_10);
|
||||
StorageDead(_8);
|
||||
StorageLive(_19);
|
||||
StorageLive(_14);
|
||||
_14 = &_7;
|
||||
StorageLive(_16);
|
||||
StorageLive(_15);
|
||||
_15 = copy _5;
|
||||
_16 = &_15;
|
||||
StorageLive(_17);
|
||||
_17 = copy ((*_3).3: usize);
|
||||
StorageLive(_18);
|
||||
_18 = copy _6;
|
||||
_19 = &_18;
|
||||
StorageLive(_20);
|
||||
_20 = copy ((*_9).3: usize);
|
||||
StorageLive(_21);
|
||||
_21 = copy ((*_5).1: usize);
|
||||
_22 = Le(move _20, move _21);
|
||||
StorageDead(_21);
|
||||
StorageDead(_20);
|
||||
switchInt(move _22) -> [0: bb3, otherwise: bb8];
|
||||
_18 = copy ((*_3).1: usize);
|
||||
_19 = Le(move _17, move _18);
|
||||
StorageDead(_18);
|
||||
StorageDead(_17);
|
||||
switchInt(move _19) -> [0: bb3, otherwise: bb8];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_18);
|
||||
StorageDead(_19);
|
||||
StorageDead(_17);
|
||||
StorageDead(_15);
|
||||
StorageDead(_16);
|
||||
StorageDead(_14);
|
||||
goto -> bb4;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageLive(_28);
|
||||
StorageLive(_23);
|
||||
_23 = &_8;
|
||||
StorageLive(_25);
|
||||
StorageLive(_24);
|
||||
_24 = copy _4;
|
||||
_25 = &_24;
|
||||
StorageLive(_26);
|
||||
_26 = copy ((*_7).2: usize);
|
||||
StorageLive(_27);
|
||||
_27 = copy ((*_3).0: usize);
|
||||
_28 = Le(move _26, move _27);
|
||||
StorageDead(_27);
|
||||
StorageDead(_26);
|
||||
switchInt(move _28) -> [0: bb5, otherwise: bb6];
|
||||
StorageLive(_20);
|
||||
_20 = &_6;
|
||||
StorageLive(_22);
|
||||
StorageLive(_21);
|
||||
_21 = copy _4;
|
||||
_22 = &_21;
|
||||
_23 = Le(copy _12, copy _11);
|
||||
switchInt(move _23) -> [0: bb5, otherwise: bb6];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_24);
|
||||
StorageDead(_25);
|
||||
StorageDead(_23);
|
||||
StorageDead(_21);
|
||||
StorageDead(_22);
|
||||
StorageDead(_20);
|
||||
_0 = const false;
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_24);
|
||||
StorageDead(_21);
|
||||
StorageDead(_22);
|
||||
StorageDead(_20);
|
||||
StorageLive(_24);
|
||||
_24 = &_5;
|
||||
StorageLive(_26);
|
||||
StorageLive(_25);
|
||||
_25 = copy _7;
|
||||
_26 = &_25;
|
||||
StorageLive(_27);
|
||||
_27 = copy ((*_3).1: usize);
|
||||
StorageLive(_28);
|
||||
_28 = copy ((*_3).3: usize);
|
||||
_0 = Le(move _27, move _28);
|
||||
StorageDead(_28);
|
||||
StorageDead(_27);
|
||||
StorageDead(_25);
|
||||
StorageDead(_23);
|
||||
StorageLive(_29);
|
||||
_29 = &_6;
|
||||
StorageLive(_31);
|
||||
StorageLive(_30);
|
||||
_30 = copy _10;
|
||||
_31 = &_30;
|
||||
StorageLive(_32);
|
||||
_32 = copy ((*_5).1: usize);
|
||||
StorageLive(_33);
|
||||
_33 = copy ((*_9).3: usize);
|
||||
_0 = Le(move _32, move _33);
|
||||
StorageDead(_33);
|
||||
StorageDead(_32);
|
||||
StorageDead(_30);
|
||||
StorageDead(_31);
|
||||
StorageDead(_29);
|
||||
StorageDead(_26);
|
||||
StorageDead(_24);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_28);
|
||||
StorageDead(_23);
|
||||
goto -> bb9;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_18);
|
||||
StorageDead(_19);
|
||||
StorageDead(_17);
|
||||
StorageDead(_15);
|
||||
StorageDead(_16);
|
||||
StorageDead(_14);
|
||||
_0 = const true;
|
||||
goto -> bb9;
|
||||
}
|
||||
|
||||
bb9: {
|
||||
StorageDead(_22);
|
||||
StorageDead(_16);
|
||||
StorageDead(_19);
|
||||
StorageDead(_13);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,46 +4,40 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
|
|||
let mut _0: bool;
|
||||
let mut _3: &(usize, usize, usize, usize);
|
||||
let _4: usize;
|
||||
let mut _5: &(usize, usize, usize, usize);
|
||||
let _5: usize;
|
||||
let _6: usize;
|
||||
let mut _7: &(usize, usize, usize, usize);
|
||||
let _8: usize;
|
||||
let mut _9: &(usize, usize, usize, usize);
|
||||
let _10: usize;
|
||||
let mut _11: bool;
|
||||
let mut _12: bool;
|
||||
let mut _13: bool;
|
||||
let _7: usize;
|
||||
let mut _8: bool;
|
||||
let mut _9: bool;
|
||||
let mut _10: bool;
|
||||
scope 1 {
|
||||
debug a => _4;
|
||||
debug b => _6;
|
||||
debug c => _8;
|
||||
debug d => _10;
|
||||
debug b => _5;
|
||||
debug c => _6;
|
||||
debug d => _7;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_3 = copy (*_2);
|
||||
_4 = copy ((*_3).0: usize);
|
||||
_5 = copy (*_2);
|
||||
_6 = copy ((*_5).1: usize);
|
||||
_7 = copy (*_2);
|
||||
_8 = copy ((*_7).2: usize);
|
||||
_9 = copy (*_2);
|
||||
_10 = copy ((*_9).3: usize);
|
||||
StorageLive(_11);
|
||||
_11 = Le(copy _4, copy _8);
|
||||
switchInt(move _11) -> [0: bb2, otherwise: bb1];
|
||||
_5 = copy ((*_3).1: usize);
|
||||
_6 = copy ((*_3).2: usize);
|
||||
_7 = copy ((*_3).3: usize);
|
||||
StorageLive(_8);
|
||||
_8 = Le(copy _4, copy _6);
|
||||
switchInt(move _8) -> [0: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageLive(_12);
|
||||
_12 = Le(copy _10, copy _6);
|
||||
switchInt(move _12) -> [0: bb2, otherwise: bb6];
|
||||
StorageLive(_9);
|
||||
_9 = Le(copy _7, copy _5);
|
||||
switchInt(move _9) -> [0: bb2, otherwise: bb6];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_13);
|
||||
_13 = Le(copy _8, copy _4);
|
||||
switchInt(move _13) -> [0: bb3, otherwise: bb4];
|
||||
StorageLive(_10);
|
||||
_10 = Le(copy _6, copy _4);
|
||||
switchInt(move _10) -> [0: bb3, otherwise: bb4];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
|
@ -52,12 +46,12 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
|
|||
}
|
||||
|
||||
bb4: {
|
||||
_0 = Le(copy _6, copy _10);
|
||||
_0 = Le(copy _5, copy _7);
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_13);
|
||||
StorageDead(_10);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
|
@ -67,8 +61,8 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
|
|||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_12);
|
||||
StorageDead(_11);
|
||||
StorageDead(_9);
|
||||
StorageDead(_8);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,14 +19,14 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
|
|||
}
|
||||
|
||||
bb1: {
|
||||
_3 = move ((_1 as Ok).0: T);
|
||||
_0 = Result::<T, E>::Ok(copy _3);
|
||||
_3 = copy ((_1 as Ok).0: T);
|
||||
_0 = copy _1;
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_4 = move ((_1 as Err).0: E);
|
||||
_0 = Result::<T, E>::Err(copy _4);
|
||||
_4 = copy ((_1 as Err).0: E);
|
||||
_0 = copy _1;
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,62 +6,52 @@
|
|||
let mut _0: std::option::Option<i32>;
|
||||
let mut _2: &std::option::Option<i32>;
|
||||
let mut _3: &std::option::Option<i32>;
|
||||
let _4: &&mut std::option::Option<i32>;
|
||||
let mut _5: isize;
|
||||
let mut _7: !;
|
||||
let mut _8: std::option::Option<i32>;
|
||||
let mut _9: i32;
|
||||
let mut _10: !;
|
||||
let mut _11: &mut std::option::Option<i32>;
|
||||
let mut _4: isize;
|
||||
let mut _6: !;
|
||||
let mut _7: std::option::Option<i32>;
|
||||
let mut _8: i32;
|
||||
let mut _9: !;
|
||||
scope 1 {
|
||||
debug col => _6;
|
||||
let _6: i32;
|
||||
debug col => _5;
|
||||
let _5: i32;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = &_1;
|
||||
- _11 = deref_copy (*_4);
|
||||
- _3 = &(*_11);
|
||||
+ _11 = copy _1;
|
||||
+ _3 = &(*_1);
|
||||
_2 = get(move _3) -> [return: bb1, unwind unreachable];
|
||||
_3 = &(*_1);
|
||||
_2 = get::<Option<i32>>(move _3) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_3);
|
||||
_5 = discriminant((*_2));
|
||||
switchInt(move _5) -> [1: bb2, otherwise: bb3];
|
||||
_4 = discriminant((*_2));
|
||||
switchInt(move _4) -> [1: bb2, otherwise: bb3];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- StorageLive(_6);
|
||||
- StorageLive(_5);
|
||||
+ nop;
|
||||
_6 = copy (((*_2) as Some).0: i32);
|
||||
StorageLive(_8);
|
||||
- _8 = Option::<i32>::None;
|
||||
- (*_1) = move _8;
|
||||
+ _8 = const Option::<i32>::None;
|
||||
_5 = copy (((*_2) as Some).0: i32);
|
||||
StorageLive(_7);
|
||||
- _7 = Option::<i32>::None;
|
||||
- (*_1) = move _7;
|
||||
+ _7 = const Option::<i32>::None;
|
||||
+ (*_1) = const Option::<i32>::None;
|
||||
StorageDead(_7);
|
||||
StorageLive(_8);
|
||||
_8 = copy _5;
|
||||
- _0 = Option::<i32>::Some(move _8);
|
||||
+ _0 = Option::<i32>::Some(copy _5);
|
||||
StorageDead(_8);
|
||||
StorageLive(_9);
|
||||
_9 = copy _6;
|
||||
- _0 = Option::<i32>::Some(move _9);
|
||||
+ _0 = copy (*_2);
|
||||
StorageDead(_9);
|
||||
- StorageDead(_6);
|
||||
+ nop;
|
||||
StorageDead(_4);
|
||||
- StorageDead(_2);
|
||||
- StorageDead(_5);
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageLive(_10);
|
||||
StorageLive(_9);
|
||||
unreachable;
|
||||
}
|
||||
+ }
|
||||
|
|
|
@ -7,16 +7,23 @@
|
|||
//! This test demonstrates the behavior, and should be adjusted or removed when fixing and relanding
|
||||
//! the mir-opt.
|
||||
#![crate_type = "lib"]
|
||||
// skip-filecheck
|
||||
//@ compile-flags: -O -Zunsound-mir-opts
|
||||
//@ test-mir-pass: GVN
|
||||
#![allow(internal_features)]
|
||||
#![feature(rustc_attrs, core_intrinsics)]
|
||||
#![feature(core_intrinsics, custom_mir, rustc_attrs)]
|
||||
|
||||
use std::intrinsics::mir::*;
|
||||
|
||||
// EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff
|
||||
#[no_mangle]
|
||||
fn foo(v: &mut Option<i32>) -> Option<i32> {
|
||||
if let &Some(col) = get(&v) {
|
||||
// CHECK-LABEL: fn foo(
|
||||
// CHECK-SAME: [[v:_.*]]: &mut Option<i32>
|
||||
// CHECK: [[v_alias_1:_.*]] = &(*_1)
|
||||
// CHECK-NEXT: [[v_alias_2:_.*]] = get::<Option<i32>>(move [[v_alias_1]])
|
||||
// CHECK: (*[[v]]) = const Option::<i32>::None;
|
||||
// CHECK-NOT: _0 = copy (*[[v_alias_2]])
|
||||
// CHECK: _0 = Option::<i32>::Some
|
||||
// CHECK-NOT: _0 = copy (*[[v_alias_2]])
|
||||
if let &Some(col) = get(v) {
|
||||
*v = None;
|
||||
return Some(col);
|
||||
} else {
|
||||
|
@ -24,9 +31,31 @@ fn foo(v: &mut Option<i32>) -> Option<i32> {
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub enum Value {
|
||||
V0(i32),
|
||||
V1(i32),
|
||||
}
|
||||
|
||||
// EMIT_MIR simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
|
||||
#[custom_mir(dialect = "runtime", phase = "initial")]
|
||||
fn set_discriminant(v: &mut Value) -> Value {
|
||||
// CHECK-LABEL: fn set_discriminant(
|
||||
mir! {
|
||||
let v_: &Value;
|
||||
{
|
||||
Call(v_ = get(v), ReturnTo(ret), UnwindUnreachable())
|
||||
}
|
||||
ret = {
|
||||
let col: i32 = Field(Variant(*v_, 0), 0);
|
||||
SetDiscriminant(*v, 1);
|
||||
RET = Value::V0(col);
|
||||
Return()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[rustc_nounwind]
|
||||
fn get(v: &Option<i32>) -> &Option<i32> {
|
||||
fn get<T>(v: &T) -> &T {
|
||||
v
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
- // MIR for `set_discriminant` before GVN
|
||||
+ // MIR for `set_discriminant` after GVN
|
||||
|
||||
fn set_discriminant(_1: &mut Value) -> Value {
|
||||
let mut _0: Value;
|
||||
let mut _2: &Value;
|
||||
let mut _3: i32;
|
||||
|
||||
bb0: {
|
||||
_2 = get::<Value>(copy _1) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_3 = copy (((*_2) as variant#0).0: i32);
|
||||
discriminant((*_1)) = 1;
|
||||
_0 = Value::V0(copy _3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue