Skip to content

Commit

Permalink
Auto merge of #123602 - cjgillot:gvn-borrowed, r=oli-obk
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed May 3, 2024
2 parents befabbc + c19866f commit d2d24e3
Show file tree
Hide file tree
Showing 30 changed files with 591 additions and 302 deletions.
41 changes: 14 additions & 27 deletions compiler/rustc_mir_transform/src/copy_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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>,
}

Expand All @@ -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) => {}
Expand All @@ -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) {
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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
Expand All @@ -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: &[] };
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_transform/src/normalize_array_len.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_transform/src/ref_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
55 changes: 43 additions & 12 deletions compiler/rustc_mir_transform/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
//! 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;
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.
Expand All @@ -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> {
Expand All @@ -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);
Expand All @@ -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);

Expand All @@ -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(),
};
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<'_, '_> {
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions tests/coverage/issue-83601.cov-map
Original file line number Diff line number Diff line change
@@ -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)

22 changes: 11 additions & 11 deletions tests/coverage/issue-84561.cov-map
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
40 changes: 0 additions & 40 deletions tests/crashes/111883.rs

This file was deleted.

Loading

0 comments on commit d2d24e3

Please sign in to comment.