Auto merge of #123602 - cjgillot:gvn-borrowed, r=oli-obk

Account for immutably borrowed locals in MIR copy-prop and GVN

For the most part, we consider that immutably borrowed `Freeze` locals still fulfill SSA conditions. As the borrow is immutable, any use of the local will have the value given by the single assignment, and there can be no surprise.

This allows copy-prop to merge a non-borrowed local with a borrowed local. We chose to keep copy-classes heads unborrowed, as those may be easier to optimize in later passes.

This also allows to GVN the value behind an immutable borrow. If a SSA local is borrowed, dereferencing that borrow is equivalent to copying the local's value: re-executing the assignment between the borrow and the dereference would be UB.

r? `@ghost` for perf
This commit is contained in:
bors 2024-05-03 21:50:13 +00:00
commit d2d24e395a
30 changed files with 593 additions and 304 deletions

View File

@ -3,7 +3,6 @@ use rustc_index::IndexSlice;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::borrowed_locals;
use crate::ssa::SsaLocals;
@ -32,8 +31,8 @@ impl<'tcx> MirPass<'tcx> for CopyProp {
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let borrowed_locals = borrowed_locals(body);
let ssa = SsaLocals::new(body);
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let ssa = SsaLocals::new(tcx, body, param_env);
let fully_moved = fully_moved_locals(&ssa, body);
debug!(?fully_moved);
@ -51,7 +50,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
tcx,
copy_classes: ssa.copy_classes(),
fully_moved,
borrowed_locals,
borrowed_locals: ssa.borrowed_locals(),
storage_to_remove,
}
.visit_body_preserves_cfg(body);
@ -101,7 +100,7 @@ struct Replacer<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
fully_moved: BitSet<Local>,
storage_to_remove: BitSet<Local>,
borrowed_locals: BitSet<Local>,
borrowed_locals: &'a BitSet<Local>,
copy_classes: &'a IndexSlice<Local, Local>,
}
@ -112,6 +111,12 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
let new_local = self.copy_classes[*local];
// We must not unify two locals that are borrowed. But this is fine if one is borrowed and
// the other is not. We chose to check the original local, and not the target. That way, if
// the original local is borrowed and the target is not, we do not pessimize the whole class.
if self.borrowed_locals.contains(*local) {
return;
}
match ctxt {
// Do not modify the local in storage statements.
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
@ -122,32 +127,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
}
}
fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
if let Some(new_projection) = self.process_projection(place.projection, loc) {
place.projection = self.tcx().mk_place_elems(&new_projection);
}
let observes_address = match ctxt {
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::FakeBorrow
| NonMutatingUseContext::AddressOf,
) => true,
// For debuginfo, merging locals is ok.
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
self.borrowed_locals.contains(place.local)
}
_ => false,
};
if observes_address && !place.is_indirect() {
// We observe the address of `place.local`. Do not replace it.
} else {
self.visit_local(
&mut place.local,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
loc,
)
}
// Any non-mutating use context is ok.
let ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
self.visit_local(&mut place.local, ctxt, loc)
}
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {

View File

@ -121,7 +121,7 @@ impl<'tcx> MirPass<'tcx> for GVN {
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let ssa = SsaLocals::new(body);
let ssa = SsaLocals::new(tcx, body, param_env);
// Clone dominators as we need them while mutating the body.
let dominators = body.basic_blocks.dominators().clone();
@ -724,6 +724,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
// Invariant: `value` holds the value up-to the `index`th projection excluded.
let mut value = self.locals[place.local]?;
for (index, proj) in place.projection.iter().enumerate() {
if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
&& let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
&& let AddressKind::Ref(BorrowKind::Shared) = kind
&& let Some(v) = self.simplify_place_value(&mut pointee, location)
{
value = v;
place_ref = pointee.project_deeper(&place.projection[index..], self.tcx).as_ref();
}
if let Some(local) = self.try_as_local(value, location) {
// Both `local` and `Place { local: place.local, projection: projection[..index] }`
// hold the same value. Therefore, following place holds the value in the original
@ -735,6 +743,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
value = self.project(base, value, proj)?;
}
if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
&& let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
&& let AddressKind::Ref(BorrowKind::Shared) = kind
&& let Some(v) = self.simplify_place_value(&mut pointee, location)
{
value = v;
place_ref = pointee.project_deeper(&[], self.tcx).as_ref();
}
if let Some(new_local) = self.try_as_local(value, location) {
place_ref = PlaceRef { local: new_local, projection: &[] };
}

View File

@ -22,7 +22,8 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
}
fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let ssa = SsaLocals::new(body);
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let ssa = SsaLocals::new(tcx, body, param_env);
let slice_lengths = compute_slice_length(tcx, &ssa, body);
debug!(?slice_lengths);

View File

@ -82,7 +82,8 @@ impl<'tcx> MirPass<'tcx> for ReferencePropagation {
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
let ssa = SsaLocals::new(body);
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let ssa = SsaLocals::new(tcx, body, param_env);
let mut replacer = compute_replacement(tcx, body, &ssa);
debug!(?replacer.targets);

View File

@ -2,8 +2,9 @@
//! 1/ They are only assigned-to once, either as a function parameter, or in an assign statement;
//! 2/ This single assignment dominates all uses;
//!
//! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are
//! `Freeze`, as we do not track that the assignment dominates all uses of the borrow.
//! As we do not track indirect assignments, a local that has its address taken (either by
//! AddressOf or by borrowing) is considered non-SSA. However, it is UB to modify through an
//! immutable borrow of a `Freeze` local. Those can still be considered to be SSA.
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
@ -11,6 +12,7 @@ use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::{ParamEnv, TyCtxt};
pub struct SsaLocals {
/// Assignments to each local. This defines whether the local is SSA.
@ -24,6 +26,8 @@ pub struct SsaLocals {
/// Number of "direct" uses of each local, ie. uses that are not dereferences.
/// We ignore non-uses (Storage statements, debuginfo).
direct_uses: IndexVec<Local, u32>,
/// Set of SSA locals that are immutably borrowed.
borrowed_locals: BitSet<Local>,
}
pub enum AssignedValue<'a, 'tcx> {
@ -33,15 +37,22 @@ pub enum AssignedValue<'a, 'tcx> {
}
impl SsaLocals {
pub fn new<'tcx>(body: &Body<'tcx>) -> SsaLocals {
pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ParamEnv<'tcx>) -> SsaLocals {
let assignment_order = Vec::with_capacity(body.local_decls.len());
let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
let dominators = body.basic_blocks.dominators();
let direct_uses = IndexVec::from_elem(0, &body.local_decls);
let mut visitor =
SsaVisitor { body, assignments, assignment_order, dominators, direct_uses };
let borrowed_locals = BitSet::new_empty(body.local_decls.len());
let mut visitor = SsaVisitor {
body,
assignments,
assignment_order,
dominators,
direct_uses,
borrowed_locals,
};
for local in body.args_iter() {
visitor.assignments[local] = Set1::One(DefLocation::Argument);
@ -58,6 +69,16 @@ impl SsaLocals {
visitor.visit_var_debug_info(var_debug_info);
}
// The immutability of shared borrows only works on `Freeze` locals. If the visitor found
// borrows, we need to check the types. For raw pointers and mutable borrows, the locals
// have already been marked as non-SSA.
debug!(?visitor.borrowed_locals);
for local in visitor.borrowed_locals.iter() {
if !body.local_decls[local].ty.is_freeze(tcx, param_env) {
visitor.assignments[local] = Set1::Many;
}
}
debug!(?visitor.assignments);
debug!(?visitor.direct_uses);
@ -70,6 +91,7 @@ impl SsaLocals {
assignments: visitor.assignments,
assignment_order: visitor.assignment_order,
direct_uses: visitor.direct_uses,
borrowed_locals: visitor.borrowed_locals,
// This is filled by `compute_copy_classes`.
copy_classes: IndexVec::default(),
};
@ -174,6 +196,11 @@ impl SsaLocals {
&self.copy_classes
}
/// Set of SSA locals that are immutably borrowed.
pub fn borrowed_locals(&self) -> &BitSet<Local> {
&self.borrowed_locals
}
/// Make a property uniform on a copy equivalence class by removing elements.
pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) {
// Consolidate to have a local iff all its copies are.
@ -208,6 +235,8 @@ struct SsaVisitor<'tcx, 'a> {
assignments: IndexVec<Local, Set1<DefLocation>>,
assignment_order: Vec<Local>,
direct_uses: IndexVec<Local, u32>,
// Track locals that are immutably borrowed, so we can check their type is `Freeze` later.
borrowed_locals: BitSet<Local>,
}
impl SsaVisitor<'_, '_> {
@ -232,16 +261,18 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
| PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => bug!(),
// Anything can happen with raw pointers, so remove them.
// We do not verify that all uses of the borrow dominate the assignment to `local`,
// so we have to remove them too.
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::FakeBorrow
| NonMutatingUseContext::AddressOf,
)
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
| PlaceContext::MutatingUse(_) => {
self.assignments[local] = Set1::Many;
}
// Immutable borrows are ok, but we need to delay a check that the type is `Freeze`.
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow,
) => {
self.borrowed_locals.insert(local);
self.check_dominates(local, loc);
self.direct_uses[local] += 1;
}
PlaceContext::NonMutatingUse(_) => {
self.check_dominates(local, loc);
self.direct_uses[local] += 1;

View File

@ -1,12 +1,12 @@
Function name: issue_83601::main
Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
Raw bytes (21): 0x[01, 01, 01, 05, 00, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 1
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
- expression 0 operands: lhs = Counter(1), rhs = Zero
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28)
- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28)
- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2)
= (c1 - c2)
= (c1 - Zero)

View File

@ -77,22 +77,22 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10)
Function name: issue_84561::test3
Raw bytes (436): 0x[01, 01, 41, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 00, fe, 01, 82, 02, 00, 69, 6d, 69, 6d, 82, 02, 00, 69, 6d, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
Raw bytes (436): 0x[01, 01, 41, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 00, fe, 01, 82, 02, 00, 69, 6d, 69, 6d, 82, 02, 00, 69, 6d, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 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: 65
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
- expression 0 operands: lhs = Counter(1), rhs = Zero
- expression 1 operands: lhs = Counter(3), rhs = Zero
- expression 2 operands: lhs = Counter(5), rhs = Counter(6)
- expression 2 operands: lhs = Counter(5), rhs = Zero
- expression 3 operands: lhs = Expression(4, Sub), rhs = Zero
- expression 4 operands: lhs = Counter(5), rhs = Counter(6)
- expression 4 operands: lhs = Counter(5), rhs = Zero
- expression 5 operands: lhs = Counter(8), rhs = Zero
- expression 6 operands: lhs = Expression(7, Sub), rhs = Zero
- expression 7 operands: lhs = Counter(8), rhs = Zero
- expression 8 operands: lhs = Counter(12), rhs = Zero
- expression 9 operands: lhs = Counter(15), rhs = Counter(16)
- expression 9 operands: lhs = Counter(15), rhs = Zero
- expression 10 operands: lhs = Expression(11, Sub), rhs = Counter(17)
- expression 11 operands: lhs = Counter(15), rhs = Counter(16)
- expression 11 operands: lhs = Counter(15), rhs = Zero
- expression 12 operands: lhs = Expression(16, Sub), rhs = Counter(18)
- expression 13 operands: lhs = Counter(17), rhs = Zero
- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(20)
@ -150,15 +150,15 @@ Number of file 0 mappings: 51
- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28)
- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28)
- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 4, 31)
= (c1 - c2)
= (c1 - Zero)
- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 31)
- Code(Expression(1, Sub)) at (prev + 1, 5) to (start + 0, 31)
= (c3 - Zero)
- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28)
- Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 31)
= (c5 - c6)
= (c5 - Zero)
- Code(Expression(3, Sub)) at (prev + 1, 5) to (start + 0, 15)
= ((c5 - c6) - Zero)
= ((c5 - Zero) - Zero)
- Code(Zero) at (prev + 0, 32) to (start + 0, 48)
- Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15)
- Code(Zero) at (prev + 3, 32) to (start + 0, 48)
@ -176,10 +176,10 @@ Number of file 0 mappings: 51
= (c12 - Zero)
- Code(Counter(15)) at (prev + 4, 9) to (start + 4, 6)
- Code(Expression(11, Sub)) at (prev + 5, 8) to (start + 0, 15)
= (c15 - c16)
= (c15 - Zero)
- Code(Counter(17)) at (prev + 1, 9) to (start + 3, 10)
- Code(Expression(10, Sub)) at (prev + 5, 9) to (start + 3, 10)
= ((c15 - c16) - c17)
= ((c15 - Zero) - c17)
- Code(Expression(15, Add)) at (prev + 5, 8) to (start + 0, 15)
= ((c17 - Zero) + c18)
- Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19)

View File

@ -1,40 +0,0 @@
//@ known-bug: #111883
#![crate_type = "lib"]
#![feature(arbitrary_self_types, no_core, lang_items)]
#![no_core]
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
#[lang = "receiver"]
trait Receiver {}
#[lang = "dispatch_from_dyn"]
trait DispatchFromDyn<T> {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
#[lang = "unsize"]
trait Unsize<T: ?Sized> {}
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T: ?Sized> {}
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
#[lang = "drop_in_place"]
fn drop_in_place_fn<T>(a: &dyn Trait2<T>) {}
pub trait Trait1 {
fn foo(&self);
}
pub struct Type1;
impl Trait1 for Type1 {
fn foo(&self) {}
}
pub trait Trait2<T> {}
pub fn bar1() {
let a = Type1;
let b = &a as &dyn Trait1;
b.foo();
}

View File

@ -0,0 +1,24 @@
- // MIR for `borrowed` before CopyProp
+ // MIR for `borrowed` after CopyProp
fn borrowed(_1: T) -> bool {
let mut _0: bool;
let mut _2: T;
let mut _3: &T;
bb0: {
- _2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
}
bb1: {
- _0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
+ _0 = opaque::<T>(_1) -> [return: bb2, unwind unreachable];
}
bb2: {
return;
}
}

View File

@ -0,0 +1,24 @@
- // MIR for `borrowed` before CopyProp
+ // MIR for `borrowed` after CopyProp
fn borrowed(_1: T) -> bool {
let mut _0: bool;
let mut _2: T;
let mut _3: &T;
bb0: {
- _2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
}
bb1: {
- _0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
+ _0 = opaque::<T>(_1) -> [return: bb2, unwind continue];
}
bb2: {
return;
}
}

View File

@ -1,7 +1,7 @@
- // MIR for `f` before CopyProp
+ // MIR for `f` after CopyProp
- // MIR for `compare_address` before CopyProp
+ // MIR for `compare_address` after CopyProp
fn f() -> bool {
fn compare_address() -> bool {
let mut _0: bool;
let mut _1: u8;
let mut _2: &u8;

View File

@ -1,7 +1,7 @@
- // MIR for `f` before CopyProp
+ // MIR for `f` after CopyProp
- // MIR for `compare_address` before CopyProp
+ // MIR for `compare_address` after CopyProp
fn f() -> bool {
fn compare_address() -> bool {
let mut _0: bool;
let mut _1: u8;
let mut _2: &u8;

View File

@ -0,0 +1,23 @@
- // MIR for `non_freeze` before CopyProp
+ // MIR for `non_freeze` after CopyProp
fn non_freeze(_1: T) -> bool {
let mut _0: bool;
let mut _2: T;
let mut _3: &T;
bb0: {
_2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
}
bb1: {
_0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
}
bb2: {
return;
}
}

View File

@ -0,0 +1,23 @@
- // MIR for `non_freeze` before CopyProp
+ // MIR for `non_freeze` after CopyProp
fn non_freeze(_1: T) -> bool {
let mut _0: bool;
let mut _2: T;
let mut _3: &T;
bb0: {
_2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
}
bb1: {
_0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
}
bb2: {
return;
}
}

View File

@ -1,10 +1,10 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ test-mir-pass: CopyProp
#![feature(custom_mir, core_intrinsics)]
#![feature(custom_mir, core_intrinsics, freeze)]
#![allow(unused_assignments)]
extern crate core;
use core::marker::Freeze;
use core::intrinsics::mir::*;
fn opaque(_: impl Sized) -> bool { true }
@ -14,7 +14,16 @@ fn cmp_ref(a: &u8, b: &u8) -> bool {
}
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn f() -> bool {
fn compare_address() -> bool {
// CHECK-LABEL: fn compare_address(
// CHECK: bb0: {
// CHECK-NEXT: _1 = const 5_u8;
// CHECK-NEXT: _2 = &_1;
// CHECK-NEXT: _3 = _1;
// CHECK-NEXT: _4 = &_3;
// CHECK-NEXT: _0 = cmp_ref(_2, _4)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<u8>(_3)
mir!(
{
let a = 5_u8;
@ -34,8 +43,60 @@ fn f() -> bool {
)
}
fn main() {
assert!(!f());
/// Generic type `T` is `Freeze`, so shared borrows are immutable.
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn borrowed<T: Copy + Freeze>(x: T) -> bool {
// CHECK-LABEL: fn borrowed(
// CHECK: bb0: {
// CHECK-NEXT: _3 = &_1;
// CHECK-NEXT: _0 = opaque::<&T>(_3)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(_1)
mir!(
{
let a = x;
let r1 = &x;
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
}
next = {
Call(RET = opaque(a), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
)
}
// EMIT_MIR borrowed_local.f.CopyProp.diff
/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn non_freeze<T: Copy>(x: T) -> bool {
// CHECK-LABEL: fn non_freeze(
// CHECK: bb0: {
// CHECK-NEXT: _2 = _1;
// CHECK-NEXT: _3 = &_1;
// CHECK-NEXT: _0 = opaque::<&T>(_3)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(_2)
mir!(
{
let a = x;
let r1 = &x;
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
}
next = {
Call(RET = opaque(a), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
)
}
fn main() {
assert!(!compare_address());
non_freeze(5);
}
// EMIT_MIR borrowed_local.compare_address.CopyProp.diff
// EMIT_MIR borrowed_local.borrowed.CopyProp.diff
// EMIT_MIR borrowed_local.non_freeze.CopyProp.diff

View File

@ -0,0 +1,29 @@
- // MIR for `borrowed` before GVN
+ // MIR for `borrowed` after GVN
fn borrowed(_1: T) -> () {
let mut _0: ();
let mut _2: T;
let mut _3: &T;
bb0: {
_2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
}
bb1: {
- _0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
+ _0 = opaque::<T>(_1) -> [return: bb2, unwind unreachable];
}
bb2: {
- _0 = opaque::<T>((*_3)) -> [return: bb3, unwind unreachable];
+ _0 = opaque::<T>(_1) -> [return: bb3, unwind unreachable];
}
bb3: {
return;
}
}

View File

@ -0,0 +1,29 @@
- // MIR for `borrowed` before GVN
+ // MIR for `borrowed` after GVN
fn borrowed(_1: T) -> () {
let mut _0: ();
let mut _2: T;
let mut _3: &T;
bb0: {
_2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
}
bb1: {
- _0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
+ _0 = opaque::<T>(_1) -> [return: bb2, unwind continue];
}
bb2: {
- _0 = opaque::<T>((*_3)) -> [return: bb3, unwind continue];
+ _0 = opaque::<T>(_1) -> [return: bb3, unwind continue];
}
bb3: {
return;
}
}

View File

@ -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:610:19: 610:21};
let mut _9: {closure@$DIR/gvn.rs:612:19: 612:21};
let _10: ();
let mut _11: fn();
let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
let mut _13: {closure@$DIR/gvn.rs:612:19: 612: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:610:19: 610:21};
let _7: {closure@$DIR/gvn.rs:612:19: 612:21};
scope 3 {
debug closure => _7;
let _8: fn();
@ -62,16 +62,16 @@
StorageDead(_6);
StorageDead(_5);
- StorageLive(_7);
- _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
- _7 = {closure@$DIR/gvn.rs:612:19: 612:21};
- StorageLive(_8);
+ nop;
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
+ nop;
StorageLive(_9);
- _9 = _7;
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
StorageDead(_9);
StorageLive(_10);
StorageLive(_11);
@ -88,8 +88,8 @@
StorageLive(_13);
- _13 = _7;
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);

View File

@ -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:610:19: 610:21};
let mut _9: {closure@$DIR/gvn.rs:612:19: 612:21};
let _10: ();
let mut _11: fn();
let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
let mut _13: {closure@$DIR/gvn.rs:612:19: 612: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:610:19: 610:21};
let _7: {closure@$DIR/gvn.rs:612:19: 612:21};
scope 3 {
debug closure => _7;
let _8: fn();
@ -62,16 +62,16 @@
StorageDead(_6);
StorageDead(_5);
- StorageLive(_7);
- _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
- _7 = {closure@$DIR/gvn.rs:612:19: 612:21};
- StorageLive(_8);
+ nop;
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
+ nop;
StorageLive(_9);
- _9 = _7;
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
StorageDead(_9);
StorageLive(_10);
StorageLive(_11);
@ -88,8 +88,8 @@
StorageLive(_13);
- _13 = _7;
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);

View File

@ -0,0 +1,27 @@
- // MIR for `non_freeze` before GVN
+ // MIR for `non_freeze` after GVN
fn non_freeze(_1: T) -> () {
let mut _0: ();
let mut _2: T;
let mut _3: &T;
bb0: {
_2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
}
bb1: {
_0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
}
bb2: {
_0 = opaque::<T>((*_3)) -> [return: bb3, unwind unreachable];
}
bb3: {
return;
}
}

View File

@ -0,0 +1,27 @@
- // MIR for `non_freeze` before GVN
+ // MIR for `non_freeze` after GVN
fn non_freeze(_1: T) -> () {
let mut _0: ();
let mut _2: T;
let mut _3: &T;
bb0: {
_2 = _1;
_3 = &_1;
_0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
}
bb1: {
_0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
}
bb2: {
_0 = opaque::<T>((*_3)) -> [return: bb3, unwind continue];
}
bb3: {
return;
}
}

View File

@ -6,9 +6,11 @@
#![feature(rustc_attrs)]
#![feature(custom_mir)]
#![feature(core_intrinsics)]
#![feature(freeze)]
#![allow(unconditional_panic)]
use std::intrinsics::mir::*;
use std::marker::Freeze;
use std::mem::transmute;
struct S<T>(T);
@ -720,6 +722,65 @@ fn wide_ptr_integer() {
opaque(a >= b);
}
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn borrowed<T: Copy + Freeze>(x: T) {
// CHECK-LABEL: fn borrowed(
// CHECK: bb0: {
// CHECK-NEXT: _2 = _1;
// CHECK-NEXT: _3 = &_1;
// CHECK-NEXT: _0 = opaque::<&T>(_3)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(_1)
// CHECK: bb2: {
// CHECK-NEXT: _0 = opaque::<T>(_1)
mir!(
{
let a = x;
let r1 = &x;
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
}
next = {
Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
}
deref = {
Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
)
}
/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn non_freeze<T: Copy>(x: T) {
// CHECK-LABEL: fn non_freeze(
// CHECK: bb0: {
// CHECK-NEXT: _2 = _1;
// CHECK-NEXT: _3 = &_1;
// CHECK-NEXT: _0 = opaque::<&T>(_3)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(_2)
// CHECK: bb2: {
// CHECK-NEXT: _0 = opaque::<T>((*_3))
mir!(
{
let a = x;
let r1 = &x;
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
}
next = {
Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
}
deref = {
Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
)
}
fn main() {
subexpression_elimination(2, 4, 5);
wrap_unwrap(5);
@ -742,6 +803,8 @@ fn main() {
constant_index_overflow(&[5, 3]);
wide_ptr_provenance();
wide_ptr_integer();
borrowed(5);
non_freeze(5);
}
#[inline(never)]
@ -773,3 +836,5 @@ fn identity<T>(x: T) -> T {
// EMIT_MIR gvn.wide_ptr_provenance.GVN.diff
// EMIT_MIR gvn.wide_ptr_same_provenance.GVN.diff
// EMIT_MIR gvn.wide_ptr_integer.GVN.diff
// EMIT_MIR gvn.borrowed.GVN.diff
// EMIT_MIR gvn.non_freeze.GVN.diff

View File

@ -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 = (*_15);
+ _18 = (*_9);
+ _18 = _10;
StorageLive(_19);
- _19 = (*_16);
+ _19 = (*_12);
_17 = Eq(move _18, move _19);
- _17 = Eq(move _18, move _19);
+ _19 = _13;
+ _17 = Eq(_10, _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 = (*_41);
+ _44 = (*_35);
+ _44 = _36;
StorageLive(_45);
- _45 = (*_42);
+ _45 = (*_38);
_43 = Eq(move _44, move _45);
- _43 = Eq(move _44, move _45);
+ _45 = _39;
+ _43 = Eq(_36, _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 ();

View File

@ -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 = (*_15);
+ _18 = (*_9);
+ _18 = _10;
StorageLive(_19);
- _19 = (*_16);
+ _19 = (*_12);
_17 = Eq(move _18, move _19);
- _17 = Eq(move _18, move _19);
+ _19 = _13;
+ _17 = Eq(_10, _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 = (*_41);
+ _44 = (*_35);
+ _44 = _36;
StorageLive(_45);
- _45 = (*_42);
+ _45 = (*_38);
_43 = Eq(move _44, move _45);
- _43 = Eq(move _44, move _45);
+ _45 = _39;
+ _43 = Eq(_36, _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 ();

View File

@ -17,7 +17,8 @@
StorageLive(_3);
_5 = const f::promoted[0];
_3 = &(*_5);
_2 = ((*_3).1: E);
- _2 = ((*_3).1: E);
+ _2 = ((*_5).1: E);
StorageLive(_1);
- _1 = ((_2 as A).1: u32);
+ _1 = const 0_u32;

View File

@ -17,7 +17,8 @@
StorageLive(_3);
_5 = const f::promoted[0];
_3 = &(*_5);
_2 = ((*_3).1: E);
- _2 = ((*_3).1: E);
+ _2 = ((*_5).1: E);
StorageLive(_1);
- _1 = ((_2 as A).1: u32);
+ _1 = const 0_u32;

View File

@ -10,18 +10,18 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
let mut _8: &&usize;
let _9: &usize;
let mut _10: &&usize;
let mut _15: bool;
let mut _13: bool;
let mut _14: &&usize;
let _15: &usize;
let mut _16: &&usize;
let _17: &usize;
let mut _18: &&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;
let mut _31: bool;
let mut _32: &&usize;
let _33: &usize;
let mut _34: &&usize;
scope 1 {
debug a => _4;
debug b => _5;
@ -30,208 +30,145 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _8;
debug other => _10;
let mut _11: &usize;
let mut _12: &usize;
scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _11;
debug other => _12;
let mut _13: usize;
let mut _14: usize;
debug self => _4;
debug other => _9;
let mut _11: usize;
let mut _12: usize;
}
}
scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _16;
debug other => _18;
let mut _19: &usize;
let mut _20: &usize;
debug self => _14;
debug other => _16;
scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _19;
debug other => _20;
let mut _21: usize;
let mut _22: usize;
debug self => _7;
debug other => _15;
let mut _17: usize;
let mut _18: usize;
}
}
scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _24;
debug other => _26;
let mut _27: &usize;
let mut _28: &usize;
debug self => _20;
debug other => _22;
scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _27;
debug other => _28;
let mut _29: usize;
let mut _30: usize;
debug self => _6;
debug other => _21;
}
}
scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
debug self => _32;
debug other => _34;
let mut _35: &usize;
let mut _36: &usize;
debug self => _24;
debug other => _26;
scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
debug self => _35;
debug other => _36;
let mut _37: usize;
let mut _38: usize;
debug self => _5;
debug other => _25;
let mut _27: usize;
let mut _28: usize;
}
}
}
bb0: {
StorageLive(_4);
_3 = (*_2);
_4 = &((*_3).0: usize);
StorageLive(_5);
_5 = &((*_3).1: usize);
StorageLive(_6);
_6 = &((*_3).2: usize);
StorageLive(_7);
_7 = &((*_3).3: usize);
StorageLive(_15);
StorageLive(_13);
StorageLive(_8);
_8 = &_4;
StorageLive(_10);
StorageLive(_9);
_9 = _6;
_9 = &((*_3).2: usize);
_10 = &_9;
StorageLive(_11);
StorageLive(_12);
_11 = _4;
_12 = _9;
StorageLive(_13);
_13 = (*_11);
StorageLive(_14);
_14 = (*_12);
_15 = Le(move _13, move _14);
StorageDead(_14);
StorageDead(_13);
StorageDead(_12);
StorageDead(_11);
switchInt(move _15) -> [0: bb1, otherwise: bb2];
_11 = ((*_3).0: usize);
_12 = ((*_3).2: usize);
_13 = Le(_11, _12);
switchInt(move _13) -> [0: bb1, otherwise: bb2];
}
bb1: {
StorageDead(_9);
StorageDead(_10);
StorageDead(_8);
goto -> bb4;
}
bb2: {
StorageDead(_9);
StorageDead(_10);
StorageDead(_8);
StorageLive(_23);
StorageLive(_16);
_16 = &_7;
StorageLive(_18);
StorageLive(_17);
_17 = _5;
_18 = &_17;
StorageLive(_19);
StorageLive(_20);
_19 = _7;
_20 = _17;
StorageLive(_21);
_21 = (*_19);
StorageLive(_22);
_22 = (*_20);
_23 = Le(move _21, move _22);
StorageDead(_22);
StorageDead(_21);
StorageDead(_20);
StorageDead(_19);
switchInt(move _23) -> [0: bb3, otherwise: bb8];
StorageLive(_14);
_14 = &_7;
StorageLive(_16);
_15 = &((*_3).1: usize);
_16 = &_15;
StorageLive(_17);
_17 = ((*_3).3: usize);
StorageLive(_18);
_18 = ((*_3).1: usize);
_19 = Le(move _17, move _18);
StorageDead(_18);
StorageDead(_17);
switchInt(move _19) -> [0: bb3, otherwise: bb8];
}
bb3: {
StorageDead(_17);
StorageDead(_18);
StorageDead(_16);
StorageDead(_14);
goto -> bb4;
}
bb4: {
StorageLive(_31);
StorageLive(_24);
_24 = &_6;
StorageLive(_26);
StorageLive(_25);
_25 = _4;
_26 = &_25;
StorageLive(_27);
StorageLive(_28);
_27 = _6;
_28 = _25;
StorageLive(_29);
_29 = (*_27);
StorageLive(_30);
_30 = (*_28);
_31 = Le(move _29, move _30);
StorageDead(_30);
StorageDead(_29);
StorageDead(_28);
StorageDead(_27);
switchInt(move _31) -> [0: bb5, otherwise: bb6];
StorageLive(_23);
StorageLive(_20);
_20 = &_6;
StorageLive(_22);
_21 = &((*_3).0: usize);
_22 = &_21;
_23 = Le(_12, _11);
switchInt(move _23) -> [0: bb5, otherwise: bb6];
}
bb5: {
StorageDead(_25);
StorageDead(_26);
StorageDead(_24);
StorageDead(_22);
StorageDead(_20);
_0 = const false;
goto -> bb7;
}
bb6: {
StorageDead(_25);
StorageDead(_22);
StorageDead(_20);
StorageLive(_24);
_24 = &_5;
StorageLive(_26);
_25 = &((*_3).3: usize);
_26 = &_25;
StorageLive(_27);
_27 = ((*_3).1: usize);
StorageLive(_28);
_28 = ((*_3).3: usize);
_0 = Le(move _27, move _28);
StorageDead(_28);
StorageDead(_27);
StorageDead(_26);
StorageDead(_24);
StorageLive(_32);
_32 = &_5;
StorageLive(_34);
StorageLive(_33);
_33 = _7;
_34 = &_33;
StorageLive(_35);
StorageLive(_36);
_35 = _5;
_36 = _33;
StorageLive(_37);
_37 = (*_35);
StorageLive(_38);
_38 = (*_36);
_0 = Le(move _37, move _38);
StorageDead(_38);
StorageDead(_37);
StorageDead(_36);
StorageDead(_35);
StorageDead(_33);
StorageDead(_34);
StorageDead(_32);
goto -> bb7;
}
bb7: {
StorageDead(_31);
StorageDead(_23);
goto -> bb9;
}
bb8: {
StorageDead(_17);
StorageDead(_18);
StorageDead(_16);
StorageDead(_14);
_0 = const true;
goto -> bb9;
}
bb9: {
StorageDead(_23);
StorageDead(_15);
StorageDead(_7);
StorageDead(_6);
StorageDead(_5);
StorageDead(_4);
StorageDead(_19);
StorageDead(_13);
return;
}
}

View File

@ -247,7 +247,8 @@
StorageLive(_21);
_21 = &_20;
StorageLive(_22);
_22 = (*_20);
- _22 = (*_20);
+ _22 = _19;
StorageLive(_23);
StorageLive(_24);
_24 = _21;
@ -394,7 +395,8 @@
StorageLive(_62);
_62 = &_61;
StorageLive(_63);
_63 = (*_61);
- _63 = (*_61);
+ _63 = _60;
StorageLive(_64);
StorageLive(_65);
_65 = ();

View File

@ -260,7 +260,8 @@
StorageLive(_20);
_20 = &_19;
StorageLive(_21);
_21 = (*_19);
- _21 = (*_19);
+ _21 = _18;
StorageLive(_22);
StorageLive(_23);
_23 = _20;
@ -429,7 +430,8 @@
StorageLive(_67);
_67 = &_66;
StorageLive(_68);
_68 = (*_66);
- _68 = (*_66);
+ _68 = _65;
StorageLive(_69);
StorageLive(_70);
_70 = ();

View File

@ -49,7 +49,7 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) {
// CHECK: [[a:_.*]] = const 5_usize;
// CHECK: [[b:_.*]] = &[[a]];
// CHECK: [[d:_.*]] = &[[b]];
// CHECK: [[c:_.*]] = (*[[b]]);
// CHECK: [[c:_.*]] = [[a]];
let a = 5_usize;
let b = &a;
@ -138,8 +138,7 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) {
// CHECK: [[a:_.*]] = const 5_usize;
// CHECK: [[b:_.*]] = &[[a]];
// CHECK: [[d:_.*]] = &[[b]];
// FIXME this could be [[a]]
// CHECK: [[c:_.*]] = (*[[b]]);
// CHECK: [[c:_.*]] = [[a]];
let a = 5_usize;
let b = &a;
@ -363,7 +362,7 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con
// CHECK: [[a:_.*]] = const 5_usize;
// CHECK: [[b:_.*]] = &raw const [[a]];
// CHECK: [[d:_.*]] = &[[b]];
// CHECK: [[c:_.*]] = (*[[b]]);
// CHECK: [[c:_.*]] = [[a]];
let a = 5_usize;
let b = &raw const a;
@ -467,8 +466,7 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con
// CHECK: [[a:_.*]] = const 5_usize;
// CHECK: [[b:_.*]] = &raw const [[a]];
// CHECK: [[d:_.*]] = &[[b]];
// FIXME this could be [[a]]
// CHECK: [[c:_.*]] = (*[[b]]);
// CHECK: [[c:_.*]] = [[a]];
let a = 5_usize;
let b = &raw const a;