From f62d5cd82d080734a406ab3bafcedf04d54e4d74 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Jun 2025 09:03:40 +0000 Subject: [PATCH 1/6] Fortify test. --- ...g.aggregate.JumpThreading.panic-abort.diff | 47 +++++++++---------- ....aggregate.JumpThreading.panic-unwind.diff | 47 +++++++++---------- tests/mir-opt/jump_threading.rs | 37 ++++++++++++++- 3 files changed, 81 insertions(+), 50 deletions(-) diff --git a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff index a7551c3fb5b79..89d04c557f125 100644 --- a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-abort.diff @@ -1,51 +1,50 @@ - // MIR for `aggregate` before JumpThreading + // MIR for `aggregate` after JumpThreading - fn aggregate(_1: u8) -> u8 { - debug x => _1; + fn aggregate() -> u8 { let mut _0: u8; + let _1: u8; let _2: u8; - let _3: u8; - let mut _4: (u8, u8); - let mut _5: bool; - let mut _6: u8; + let mut _3: (u8, u8); + let mut _4: bool; + let mut _5: u8; scope 1 { - debug a => _2; - debug b => _3; + debug a => _1; + debug b => _2; } bb0: { - StorageLive(_4); - _4 = const aggregate::FOO; - StorageLive(_2); - _2 = copy (_4.0: u8); StorageLive(_3); - _3 = copy (_4.1: u8); - StorageDead(_4); + _3 = const aggregate::FOO; + StorageLive(_1); + _1 = copy (_3.0: u8); + StorageLive(_2); + _2 = copy (_3.1: u8); + StorageDead(_3); + StorageLive(_4); StorageLive(_5); - StorageLive(_6); - _6 = copy _2; - _5 = Eq(move _6, const 7_u8); -- switchInt(move _5) -> [0: bb2, otherwise: bb1]; + _5 = copy _1; + _4 = Eq(move _5, const 7_u8); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; + goto -> bb2; } bb1: { - StorageDead(_6); - _0 = copy _3; + StorageDead(_5); + _0 = copy _2; goto -> bb3; } bb2: { - StorageDead(_6); - _0 = copy _2; + StorageDead(_5); + _0 = copy _1; goto -> bb3; } bb3: { - StorageDead(_5); - StorageDead(_3); + StorageDead(_4); StorageDead(_2); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff index a7551c3fb5b79..89d04c557f125 100644 --- a/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.aggregate.JumpThreading.panic-unwind.diff @@ -1,51 +1,50 @@ - // MIR for `aggregate` before JumpThreading + // MIR for `aggregate` after JumpThreading - fn aggregate(_1: u8) -> u8 { - debug x => _1; + fn aggregate() -> u8 { let mut _0: u8; + let _1: u8; let _2: u8; - let _3: u8; - let mut _4: (u8, u8); - let mut _5: bool; - let mut _6: u8; + let mut _3: (u8, u8); + let mut _4: bool; + let mut _5: u8; scope 1 { - debug a => _2; - debug b => _3; + debug a => _1; + debug b => _2; } bb0: { - StorageLive(_4); - _4 = const aggregate::FOO; - StorageLive(_2); - _2 = copy (_4.0: u8); StorageLive(_3); - _3 = copy (_4.1: u8); - StorageDead(_4); + _3 = const aggregate::FOO; + StorageLive(_1); + _1 = copy (_3.0: u8); + StorageLive(_2); + _2 = copy (_3.1: u8); + StorageDead(_3); + StorageLive(_4); StorageLive(_5); - StorageLive(_6); - _6 = copy _2; - _5 = Eq(move _6, const 7_u8); -- switchInt(move _5) -> [0: bb2, otherwise: bb1]; + _5 = copy _1; + _4 = Eq(move _5, const 7_u8); +- switchInt(move _4) -> [0: bb2, otherwise: bb1]; + goto -> bb2; } bb1: { - StorageDead(_6); - _0 = copy _3; + StorageDead(_5); + _0 = copy _2; goto -> bb3; } bb2: { - StorageDead(_6); - _0 = copy _2; + StorageDead(_5); + _0 = copy _1; goto -> bb3; } bb3: { - StorageDead(_5); - StorageDead(_3); + StorageDead(_4); StorageDead(_2); + StorageDead(_1); return; } } diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 009e1060700c1..b1d9602bd46c1 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -449,9 +449,17 @@ fn disappearing_bb(x: u8) -> u8 { } /// Verify that we can thread jumps when we assign from an aggregate constant. -fn aggregate(x: u8) -> u8 { +fn aggregate() -> u8 { // CHECK-LABEL: fn aggregate( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; // CHECK-NOT: switchInt( + // CHECK: [[a2:_.*]] = copy [[a]]; + // CHECK: {{_.*}} = Eq(move [[a2]], const 7_u8); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = copy [[a]]; const FOO: (u8, u8) = (5, 13); @@ -508,7 +516,16 @@ fn assume(a: u8, b: bool) -> u8 { /// Verify that jump threading succeeds seeing through copies of aggregates. fn aggregate_copy() -> u32 { // CHECK-LABEL: fn aggregate_copy( + // CHECK: debug a => [[a:_.*]]; + // CHECK: debug b => [[b:_.*]]; + // CHECK: debug c => [[c:_.*]]; // CHECK-NOT: switchInt( + // CHECK: [[c2:_.*]] = copy [[c]]; + // CHECK: {{_.*}} = Eq(move [[c2]], const 2_u32); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = const 13_u32; const Foo: (u32, u32) = (5, 3); @@ -532,6 +549,14 @@ fn floats() -> u32 { pub fn bitwise_not() -> i32 { // CHECK-LABEL: fn bitwise_not( + // CHECK: debug a => [[a:_.*]]; + // CHECK: [[a2:_.*]] = copy [[a]]; + // CHECK: [[not:_.*]] = Not(move [[a2]]); + // CHECK: {{_.*}} = Eq(move [[not]], const 0_i32); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = const 0_i32; // Test for #131195, which was optimizing `!a == b` into `a != b`. let a = 1; @@ -540,6 +565,14 @@ pub fn bitwise_not() -> i32 { pub fn logical_not() -> i32 { // CHECK-LABEL: fn logical_not( + // CHECK: debug a => [[a:_.*]]; + // CHECK: [[a2:_.*]] = copy [[a]]; + // CHECK: [[not:_.*]] = Not(move [[a2]]); + // CHECK: {{_.*}} = Eq(move [[not]], const true); + // CHECK-NEXT: goto -> [[bb:bb.*]]; + // CHECK: [[bb]]: { + // CHECK-NOT: } + // CHECK: _0 = const 1_i32; let a = false; if !a == true { 1 } else { 0 } @@ -557,7 +590,7 @@ fn main() { mutable_ref(); renumbered_bb(true); disappearing_bb(7); - aggregate(7); + aggregate(); assume(7, false); floats(); bitwise_not(); From cea2e2e8af92169998cd31bbe15260b09362e738 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 19 Jun 2025 22:42:05 +0000 Subject: [PATCH 2/6] Use a simpler condition set in jump threading. --- .../rustc_mir_dataflow/src/value_analysis.rs | 68 +++-- .../rustc_mir_transform/src/jump_threading.rs | 254 +++++++++++------- 2 files changed, 202 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 83fd8ccba60e5..87322a878e0b0 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -26,7 +26,7 @@ rustc_index::newtype_index!( /// This index uniquely identifies a tracked place and therefore a slot in [`State`]. /// /// It is an implementation detail of this module. - struct ValueIndex {} + pub struct ValueIndex {} ); /// See [`State`]. @@ -211,22 +211,9 @@ impl State { /// The target place must have been flooded before calling this method. pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map<'_>) { let State::Reachable(values) = self else { return }; - - // If both places are tracked, we copy the value to the target. - // If the target is tracked, but the source is not, we do nothing, as invalidation has - // already been performed. - if let Some(target_value) = map.places[target].value_index { - if let Some(source_value) = map.places[source].value_index { - values.insert(target_value, values.get(source_value).clone()); - } - } - for target_child in map.children(target) { - // Try to find corresponding child and recurse. Reasoning is similar as above. - let projection = map.places[target_child].proj_elem.unwrap(); - if let Some(source_child) = map.projections.get(&(source, projection)) { - self.insert_place_idx(target_child, *source_child, map); - } - } + map.for_each_value_pair(target, source, &mut |target, source| { + values.insert(target, values.get(source).clone()); + }); } /// Helper method to interpret `target = result`. @@ -677,6 +664,26 @@ impl<'tcx> Map<'tcx> { self.find_extra(place, [TrackElem::DerefLen]) } + /// Locates the value corresponding to the given place. + pub fn value(&self, place: PlaceIndex) -> Option { + self.places[place].value_index + } + + /// Locates the value corresponding to the given place. + pub fn find_value(&self, place: PlaceRef<'_>) -> Option { + self.value(self.find(place)?) + } + + /// Locates the value corresponding to the given discriminant. + pub fn find_discr_value(&self, place: PlaceRef<'_>) -> Option { + self.value(self.find_discr(place)?) + } + + /// Locates the value corresponding to the given length. + pub fn find_len_value(&self, place: PlaceRef<'_>) -> Option { + self.value(self.find_len(place)?) + } + /// Iterate over all direct children. fn children(&self, parent: PlaceIndex) -> impl Iterator { Children::new(self, parent) @@ -689,7 +696,7 @@ impl<'tcx> Map<'tcx> { /// /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track /// as such. - fn for_each_aliasing_place( + pub fn for_each_aliasing_place( &self, place: PlaceRef<'_>, tail_elem: Option, @@ -778,6 +785,31 @@ impl<'tcx> Map<'tcx> { } } } + + /// Recursively iterates on each value contained in `target`, paired with matching projection + /// inside `source`. + pub fn for_each_value_pair( + &self, + target: PlaceIndex, + source: PlaceIndex, + f: &mut impl FnMut(ValueIndex, ValueIndex), + ) { + // If both places are tracked, we copy the value to the target. + // If the target is tracked, but the source is not, we do nothing, as invalidation has + // already been performed. + if let Some(target_value) = self.places[target].value_index { + if let Some(source_value) = self.places[source].value_index { + f(target_value, source_value) + } + } + for target_child in self.children(target) { + // Try to find corresponding child and recurse. Reasoning is similar as above. + let projection = self.places[target_child].proj_elem.unwrap(); + if let Some(source_child) = self.projections.get(&(source, projection)) { + self.for_each_value_pair(target_child, *source_child, f); + } + } + } } /// This is the information tracked for every [`PlaceIndex`] and is stored by [`Map`]. diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index b45bff2af4478..54d5dbb655bb1 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -38,7 +38,7 @@ use rustc_arena::DroplessArena; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; @@ -48,7 +48,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; use rustc_mir_dataflow::lattice::HasBottom; -use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; +use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, TrackElem, ValueIndex}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; @@ -135,6 +135,7 @@ struct TOFinder<'a, 'tcx> { /// to `value`, jump to `target`. #[derive(Copy, Clone, Debug)] struct Condition { + place: ValueIndex, value: ScalarInt, polarity: Polarity, target: BasicBlock, @@ -147,8 +148,14 @@ enum Polarity { } impl Condition { - fn matches(&self, value: ScalarInt) -> bool { - (self.value == value) == (self.polarity == Polarity::Eq) + fn matches(&self, place: ValueIndex, value: ScalarInt) -> bool { + self.place == place && (self.value == value) == (self.polarity == Polarity::Eq) + } + + fn into_opportunity(self, match_bb: Option) -> ThreadingOpportunity { + trace!(?self, "registering"); + let chain = match_bb.into_iter().collect(); + ThreadingOpportunity { chain, target: self.target } } } @@ -164,29 +171,50 @@ impl HasBottom for ConditionSet<'_> { } impl<'a> ConditionSet<'a> { + fn is_empty(self) -> bool { + self.0.is_empty() + } + fn iter(self) -> impl Iterator { self.0.iter().copied() } - fn iter_matches(self, value: ScalarInt) -> impl Iterator { - self.iter().filter(move |c| c.matches(value)) + fn iter_matches(self, place: ValueIndex, value: ScalarInt) -> impl Iterator { + self.iter().filter(move |c| c.matches(place, value)) + } + + fn register_matches( + &self, + place: ValueIndex, + value: ScalarInt, + match_bb: Option, + opportunities: &mut Vec, + ) { + self.iter_matches(place, value) + .for_each(|cond| opportunities.push(cond.into_opportunity(match_bb))) + } + + fn filter(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> bool) -> ConditionSet<'a> { + let set = arena.alloc_from_iter(self.iter().filter(|&c| f(c))); + ConditionSet(set) } - fn map( + fn filter_map( self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Option, - ) -> Option> { - let set = arena.try_alloc_from_iter(self.iter().map(|c| f(c).ok_or(()))).ok()?; - Some(ConditionSet(set)) + ) -> ConditionSet<'a> { + let set = arena.alloc_from_iter(self.iter().filter_map(|c| f(c))); + ConditionSet(set) } -} -impl<'a, 'tcx> TOFinder<'a, 'tcx> { - fn is_empty(&self, state: &State>) -> bool { - state.all_bottom() + fn map(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Condition) -> ConditionSet<'a> { + let set = arena.alloc_from_iter(self.iter().map(|c| f(c))); + ConditionSet(set) } +} +impl<'a, 'tcx> TOFinder<'a, 'tcx> { /// Recursion entry point to find threading opportunities. #[instrument(level = "trace", skip(self))] fn start_from_switch(&mut self, bb: BasicBlock) { @@ -201,27 +229,24 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let discr_ty = discr.ty(self.body, self.tcx).ty; let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; - let Some(discr) = self.map.find(discr.as_ref()) else { return }; + let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; debug!(?discr); let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); - let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; self.arena.alloc_from_iter([ - Condition { value, polarity: Polarity::Eq, target: then }, - Condition { value, polarity: Polarity::Ne, target: else_ }, + Condition { place: discr, value, polarity: Polarity::Eq, target: then }, + Condition { place: discr, value, polarity: Polarity::Ne, target: else_ }, ]) } else { self.arena.alloc_from_iter(targets.iter().filter_map(|(value, target)| { let value = ScalarInt::try_from_uint(value, discr_layout.size)?; - Some(Condition { value, polarity: Polarity::Eq, target }) + Some(Condition { place: discr, value, polarity: Polarity::Eq, target }) })) }; - let conds = ConditionSet(conds); - state.insert_value_idx(discr, conds, &self.map); - + let state = ConditionSet(conds); self.find_opportunity(bb, state, cost, 0) } @@ -231,7 +256,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { fn find_opportunity( &mut self, bb: BasicBlock, - mut state: State>, + mut state: ConditionSet<'a>, mut cost: CostChecker<'_, 'tcx>, depth: usize, ) { @@ -244,7 +269,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { for (statement_index, stmt) in self.body.basic_blocks[bb].statements.iter().enumerate().rev() { - if self.is_empty(&state) { + if state.is_empty() { return; } @@ -261,11 +286,11 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. // _1 = 6 if let Some((lhs, tail)) = self.mutated_statement(stmt) { - state.flood_with_tail_elem(lhs.as_ref(), tail, &self.map, ConditionSet::BOTTOM); + self.flood_state(lhs, tail, &mut state); } } - if self.is_empty(&state) || depth >= MAX_BACKTRACK { + if state.is_empty() || depth >= MAX_BACKTRACK { return; } @@ -281,13 +306,13 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { self.process_switch_int(discr, targets, bb, &mut state); self.find_opportunity(pred, state, cost, depth + 1); } - _ => self.recurse_through_terminator(pred, || state, &cost, depth), + _ => self.recurse_through_terminator(pred, state, &cost, depth), } } else if let &[ref predecessors @ .., last_pred] = &predecessors[..] { for &pred in predecessors { - self.recurse_through_terminator(pred, || state.clone(), &cost, depth); + self.recurse_through_terminator(pred, state, &cost, depth); } - self.recurse_through_terminator(last_pred, || state, &cost, depth); + self.recurse_through_terminator(last_pred, state, &cost, depth); } let new_tos = &mut self.opportunities[last_non_rec..]; @@ -314,6 +339,23 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } } + /// Remove all conditions in the state that alias given place. + fn flood_state( + &self, + place: Place<'tcx>, + extra_elem: Option, + state: &mut ConditionSet<'a>, + ) { + let mut places_to_exclude = FxHashSet::default(); + self.map.for_each_aliasing_place(place.as_ref(), extra_elem, &mut |vi| { + places_to_exclude.insert(vi); + }); + if places_to_exclude.is_empty() { + return; + } + *state = state.filter(self.arena, |c| !places_to_exclude.contains(&c.place)); + } + /// Extract the mutated place from a statement. /// /// This method returns the `Place` so we can flood the state in case of a partial assignment. @@ -361,17 +403,12 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { bb: BasicBlock, lhs: PlaceIndex, rhs: ImmTy<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { - let register_opportunity = |c: Condition| { - debug!(?bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }; - - if let Some(conditions) = state.try_get_idx(lhs, &self.map) + if let Some(lhs) = self.map.value(lhs) && let Immediate::Scalar(Scalar::Int(int)) = *rhs { - conditions.iter_matches(int).for_each(register_opportunity); + state.register_matches(lhs, int, Some(bb), &mut self.opportunities); } } @@ -382,7 +419,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { bb: BasicBlock, lhs: PlaceIndex, constant: OpTy<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { self.map.for_each_projection_value( lhs, @@ -404,27 +441,38 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } }, &mut |place, op| { - if let Some(conditions) = state.try_get_idx(place, &self.map) + if let Some(place) = self.map.value(place) && let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm { - conditions.iter_matches(int).for_each(|c: Condition| { - self.opportunities - .push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }) + state.register_matches(place, int, Some(bb), &mut self.opportunities); } }, ); } + #[instrument(level = "trace", skip(self))] + fn process_copy(&mut self, lhs: PlaceIndex, rhs: PlaceIndex, state: &mut ConditionSet<'a>) { + let mut renames = FxHashMap::default(); + self.map.for_each_value_pair(rhs, lhs, &mut |rhs, lhs| { + renames.insert(lhs, rhs); + }); + *state = state.map(self.arena, |mut c| { + if let Some(rhs) = renames.get(&c.place) { + c.place = *rhs + } + c + }); + } + #[instrument(level = "trace", skip(self))] fn process_operand( &mut self, bb: BasicBlock, lhs: PlaceIndex, rhs: &Operand<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. @@ -439,7 +487,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; - state.insert_place_idx(rhs, lhs, &self.map); + self.process_copy(lhs, rhs, state) } } } @@ -449,17 +497,20 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { &mut self, bb: BasicBlock, lhs_place: &Place<'tcx>, - rhs: &Rvalue<'tcx>, - state: &mut State>, + rvalue: &Rvalue<'tcx>, + state: &mut ConditionSet<'a>, ) { let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return }; - match rhs { + match rvalue { Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), // Transfer the conditions on the copy rhs. - Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state), + Rvalue::CopyForDeref(rhs) => { + let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; + self.process_copy(lhs, rhs, state) + } Rvalue::Discriminant(rhs) => { let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; - state.insert_place_idx(rhs, lhs, &self.map); + self.process_copy(lhs, rhs, state) } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Rvalue::Aggregate(box kind, operands) => { @@ -491,32 +542,30 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } } // Transfer the conditions on the copy rhs, after inverting the value of the condition. - Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => { - let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap(); - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; - let Some(conds) = conditions.map(self.arena, |mut cond| { - cond.value = self - .ecx - .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) - .discard_err()? - .to_scalar_int() - .discard_err()?; + Rvalue::UnaryOp(UnOp::Not, Operand::Move(operand) | Operand::Copy(operand)) => { + let layout = self.ecx.layout_of(operand.ty(self.body, self.tcx).ty).unwrap(); + let Some(lhs) = self.map.value(lhs) else { return }; + let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; + *state = state.filter_map(self.arena, |mut cond| { + if cond.place == lhs { + cond.place = operand; + cond.value = self + .ecx + .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout)) + .discard_err()? + .to_scalar_int() + .discard_err()?; + } Some(cond) - }) else { - return; - }; - state.insert_value_idx(place, conds, &self.map); + }); } // We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`. // Create a condition on `rhs ?= B`. Rvalue::BinaryOp( op, - box (Operand::Move(place) | Operand::Copy(place), Operand::Constant(value)) - | box (Operand::Constant(value), Operand::Move(place) | Operand::Copy(place)), + box (Operand::Move(operand) | Operand::Copy(operand), Operand::Constant(value)) + | box (Operand::Constant(value), Operand::Move(operand) | Operand::Copy(operand)), ) => { - let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return }; - let Some(place) = self.map.find(place.as_ref()) else { return }; let equals = match op { BinOp::Eq => ScalarInt::TRUE, BinOp::Ne => ScalarInt::FALSE, @@ -529,20 +578,28 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Avoid handling them, though this could be extended in the future. return; } + let Some(lhs) = self.map.value(lhs) else { return }; + let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env) else { return; }; - let Some(conds) = conditions.map(self.arena, |c| { - Some(Condition { - value, - polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne }, - ..c - }) - }) else { - return; - }; - state.insert_value_idx(place, conds, &self.map); + *state = state.map(self.arena, |c| { + if c.place == lhs { + Condition { + place: operand, + value, + polarity: if c.matches(lhs, equals) { + Polarity::Eq + } else { + Polarity::Ne + }, + ..c + } + } else { + c + } + }); } _ => {} @@ -554,13 +611,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { &mut self, bb: BasicBlock, stmt: &Statement<'tcx>, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { - let register_opportunity = |c: Condition| { - debug!(?bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![bb], target: c.target }) - }; - // Below, `lhs` is the return value of `mutated_statement`, // the place to which `conditions` apply. @@ -584,8 +636,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { - let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return }; - conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity) + let Some(place) = self.map.find_value(place.as_ref()) else { return }; + state.register_matches(place, ScalarInt::TRUE, Some(bb), &mut self.opportunities) } StatementKind::Assign(box (lhs_place, rhs)) => { self.process_assign(bb, lhs_place, rhs, state) @@ -598,8 +650,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { fn recurse_through_terminator( &mut self, bb: BasicBlock, - // Pass a closure that may clone the state, as we don't want to do it each time. - state: impl FnOnce() -> State>, + mut state: ConditionSet<'a>, cost: &CostChecker<'_, 'tcx>, depth: usize, ) { @@ -630,9 +681,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { }; // We can recurse through this terminator. - let mut state = state(); if let Some(place_to_flood) = place_to_flood { - state.flood_with(place_to_flood.as_ref(), &self.map, ConditionSet::BOTTOM); + self.flood_state(place_to_flood, None, &mut state); } self.find_opportunity(bb, state, cost.clone(), depth + 1) } @@ -643,7 +693,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { discr: &Operand<'tcx>, targets: &SwitchTargets, target_bb: BasicBlock, - state: &mut State>, + state: &mut ConditionSet<'a>, ) { debug_assert_ne!(target_bb, START_BLOCK); debug_assert_eq!(self.body.basic_blocks.predecessors()[target_bb].len(), 1); @@ -653,7 +703,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return; }; - let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return }; + let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; @@ -663,10 +713,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // through the `SwitchInt` before arriving here. Therefore, we know that // `discr == value`. If one condition can be fulfilled by `discr == value`, // that's an opportunity. - for c in conditions.iter_matches(value) { - debug!(?target_bb, ?c.target, "register"); - self.opportunities.push(ThreadingOpportunity { chain: vec![], target: c.target }); - } + // + // The TO starts with `target_bb`, which will be added by `find_opportunity`, so we + // start with an empty bb chain. + state.register_matches(discr, value, None, &mut self.opportunities); } else if let Some((value, _, else_bb)) = targets.as_static_if() && target_bb == else_bb { @@ -675,11 +725,11 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // We only know that `discr != value`. That's much weaker information than // the equality we had in the previous arm. All we can conclude is that // the replacement condition `discr != value` can be threaded, and nothing else. - for c in conditions.iter() { - if c.value == value && c.polarity == Polarity::Ne { - debug!(?target_bb, ?c.target, "register"); - self.opportunities - .push(ThreadingOpportunity { chain: vec![], target: c.target }); + for c in state.iter() { + if c.place == discr && c.value == value && c.polarity == Polarity::Ne { + // The TO starts with `target_bb`, which will be added by `find_opportunity`, + // so we start with an empty bb chain. + self.opportunities.push(c.into_opportunity(None)); } } } From 3fa44ea40e18f966cdb522d923b9112edccd73c1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 20 Jun 2025 13:14:31 +0000 Subject: [PATCH 3/6] Split Map::register. --- .../rustc_mir_dataflow/src/value_analysis.rs | 259 ++++++++++-------- 1 file changed, 144 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 87322a878e0b0..f7751b5572e40 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -372,21 +372,20 @@ impl<'tcx> Map<'tcx> { inner_values: IndexVec::new(), inner_values_buffer: Vec::new(), }; - let exclude = excluded_locals(body); - map.register(tcx, body, exclude, value_limit); + map.register_locals(tcx, body); + map.collect_places(tcx, body); + map.propagate_assignments(tcx, body); + map.create_values(tcx, body, value_limit); + map.trim_useless_places(); debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len()); map } /// Register all non-excluded places that have scalar layout. #[tracing::instrument(level = "trace", skip(self, tcx, body))] - fn register( - &mut self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - exclude: DenseBitSet, - value_limit: Option, - ) { + fn register_locals(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let exclude = excluded_locals(body); + // Start by constructing the places for each bare local. for (local, decl) in body.local_decls.iter_enumerated() { if exclude.contains(local) { @@ -401,23 +400,79 @@ impl<'tcx> Map<'tcx> { let place = self.places.push(PlaceInfo::new(decl.ty, None)); self.locals[local] = Some(place); } + } - // Collect syntactic places and assignments between them. - let mut collector = - PlaceCollector { tcx, body, map: self, assignments: Default::default() }; + /// Collect syntactic places from body, and create `PlaceIndex` for them. + #[tracing::instrument(level = "trace", skip(self, tcx, body))] + fn collect_places(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let mut collector = PlaceCollector { tcx, body, map: self }; collector.visit_body(body); - let PlaceCollector { mut assignments, .. } = collector; - - // Just collecting syntactic places is not enough. We may need to propagate this pattern: - // _1 = (const 5u32, const 13i64); - // _2 = _1; - // _3 = (_2.0 as u32); - // - // `_1.0` does not appear, but we still need to track it. This is achieved by propagating - // projections from assignments. We recorded an assignment between `_2` and `_1`, so we - // want `_1` and `_2` to have the same sub-places. - // - // This is what this fixpoint loop does. While we are still creating places, run through + } + + /// Just collecting syntactic places is not enough. We may need to propagate this pattern: + /// _1 = (const 5u32, const 13i64); + /// _2 = _1; + /// _3 = (_2.0 as u32); + /// + /// `_1.0` does not appear, but we still need to track it. This is achieved by propagating + /// projections from assignments. We recorded an assignment between `_2` and `_1`, so we + /// want `_1` and `_2` to have the same sub-places. + #[tracing::instrument(level = "trace", skip(self, tcx, body))] + fn propagate_assignments(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + // Collect syntactic places and assignments between them. + let mut assignments = FxIndexSet::default(); + + for bbdata in body.basic_blocks.iter() { + for stmt in bbdata.statements.iter() { + let Some((lhs, rhs)) = stmt.kind.as_assign() else { continue }; + match rhs { + Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs)) + | Rvalue::CopyForDeref(rhs) => { + let Some(lhs) = self.register_place(tcx, body, *lhs) else { continue }; + let Some(rhs) = self.register_place(tcx, body, *rhs) else { continue }; + assignments.insert((lhs, rhs)); + } + Rvalue::Aggregate(kind, fields) => { + let Some(mut lhs) = self.register_place(tcx, body, *lhs) else { continue }; + match **kind { + // Do not propagate unions. + AggregateKind::Adt(_, _, _, _, Some(_)) => continue, + AggregateKind::Adt(_, variant, _, _, None) => { + let ty = self.places[lhs].ty; + if ty.is_enum() { + lhs = self.register_place_index( + ty, + lhs, + TrackElem::Variant(variant), + ); + } + } + AggregateKind::RawPtr(..) + | AggregateKind::Array(_) + | AggregateKind::Tuple + | AggregateKind::Closure(..) + | AggregateKind::Coroutine(..) + | AggregateKind::CoroutineClosure(..) => {} + } + for (index, field) in fields.iter_enumerated() { + if let Some(rhs) = field.place() + && let Some(rhs) = self.register_place(tcx, body, rhs) + { + let lhs = self.register_place_index( + self.places[rhs].ty, + lhs, + TrackElem::Field(index), + ); + assignments.insert((lhs, rhs)); + } + } + } + _ => {} + } + } + } + + // This is a fixpoint loop does. While we are still creating places, run through // all the assignments, and register places for children. let mut num_places = 0; while num_places < self.places.len() { @@ -430,8 +485,11 @@ impl<'tcx> Map<'tcx> { let mut child = self.places[lhs].first_child; while let Some(lhs_child) = child { let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[lhs_child]; - let rhs_child = - self.register_place(ty, rhs, proj_elem.expect("child is not a projection")); + let rhs_child = self.register_place_index( + ty, + rhs, + proj_elem.expect("child is not a projection"), + ); assignments.insert((lhs_child, rhs_child)); child = next_sibling; } @@ -440,16 +498,21 @@ impl<'tcx> Map<'tcx> { let mut child = self.places[rhs].first_child; while let Some(rhs_child) = child { let PlaceInfo { ty, proj_elem, next_sibling, .. } = self.places[rhs_child]; - let lhs_child = - self.register_place(ty, lhs, proj_elem.expect("child is not a projection")); + let lhs_child = self.register_place_index( + ty, + lhs, + proj_elem.expect("child is not a projection"), + ); assignments.insert((lhs_child, rhs_child)); child = next_sibling; } } } - drop(assignments); + } - // Create values for places whose type have scalar layout. + /// Create values for places whose type have scalar layout. + #[tracing::instrument(level = "trace", skip(self, tcx, body))] + fn create_values(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) { let typing_env = body.typing_env(tcx); for place_info in self.places.iter_mut() { // The user requires a bound on the number of created values. @@ -483,8 +546,11 @@ impl<'tcx> Map<'tcx> { self.cache_preorder_invoke(place); } } + } - // Trim useless places. + /// Trim useless places. + #[tracing::instrument(level = "trace", skip(self))] + fn trim_useless_places(&mut self) { for opt_place in self.locals.iter_mut() { if let Some(place) = *opt_place && self.inner_values[place].is_empty() @@ -497,7 +563,12 @@ impl<'tcx> Map<'tcx> { } #[tracing::instrument(level = "trace", skip(self), ret)] - fn register_place(&mut self, ty: Ty<'tcx>, base: PlaceIndex, elem: TrackElem) -> PlaceIndex { + fn register_place_index( + &mut self, + ty: Ty<'tcx>, + base: PlaceIndex, + elem: TrackElem, + ) -> PlaceIndex { *self.projections.entry((base, elem)).or_insert_with(|| { let next = self.places.push(PlaceInfo::new(ty, Some(elem))); self.places[next].next_sibling = self.places[base].first_child; @@ -506,6 +577,46 @@ impl<'tcx> Map<'tcx> { }) } + #[tracing::instrument(level = "trace", skip(self, tcx, body))] + fn register_place( + &mut self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + place: Place<'tcx>, + ) -> Option { + // Create a place for this projection. + let mut place_index = self.locals[place.local]?; + let mut ty = PlaceTy::from_ty(body.local_decls[place.local].ty); + tracing::trace!(?place_index, ?ty); + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.register_place_index(tcx.types.usize, place_index, TrackElem::DerefLen); + } else if ty.ty.is_enum() { + let discriminant_ty = ty.ty.discriminant_ty(tcx); + self.register_place_index(discriminant_ty, place_index, TrackElem::Discriminant); + } + + for proj in place.projection { + let track_elem = proj.try_into().ok()?; + ty = ty.projection_ty(tcx, proj); + place_index = self.register_place_index(ty.ty, place_index, track_elem); + tracing::trace!(?proj, ?place_index, ?ty); + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.register_place_index(tcx.types.usize, place_index, TrackElem::DerefLen); + } else if ty.ty.is_enum() { + let discriminant_ty = ty.ty.discriminant_ty(tcx); + self.register_place_index(discriminant_ty, place_index, TrackElem::Discriminant); + } + } + + Some(place_index) + } + /// Precompute the list of values inside `root` and store it inside /// as a slice within `inner_values_buffer`. fn cache_preorder_invoke(&mut self, root: PlaceIndex) { @@ -530,44 +641,6 @@ struct PlaceCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: &'a mut Map<'tcx>, - assignments: FxIndexSet<(PlaceIndex, PlaceIndex)>, -} - -impl<'tcx> PlaceCollector<'_, 'tcx> { - #[tracing::instrument(level = "trace", skip(self))] - fn register_place(&mut self, place: Place<'tcx>) -> Option { - // Create a place for this projection. - let mut place_index = self.map.locals[place.local]?; - let mut ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); - tracing::trace!(?place_index, ?ty); - - if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() - && let ty::Slice(..) = ref_ty.kind() - { - self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen); - } else if ty.ty.is_enum() { - let discriminant_ty = ty.ty.discriminant_ty(self.tcx); - self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); - } - - for proj in place.projection { - let track_elem = proj.try_into().ok()?; - ty = ty.projection_ty(self.tcx, proj); - place_index = self.map.register_place(ty.ty, place_index, track_elem); - tracing::trace!(?proj, ?place_index, ?ty); - - if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() - && let ty::Slice(..) = ref_ty.kind() - { - self.map.register_place(self.tcx.types.usize, place_index, TrackElem::DerefLen); - } else if ty.ty.is_enum() { - let discriminant_ty = ty.ty.discriminant_ty(self.tcx); - self.map.register_place(discriminant_ty, place_index, TrackElem::Discriminant); - } - } - - Some(place_index) - } } impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> { @@ -577,51 +650,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> { return; } - self.register_place(*place); - } - - fn visit_assign(&mut self, lhs: &Place<'tcx>, rhs: &Rvalue<'tcx>, location: Location) { - self.super_assign(lhs, rhs, location); - - match rhs { - Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs)) | Rvalue::CopyForDeref(rhs) => { - let Some(lhs) = self.register_place(*lhs) else { return }; - let Some(rhs) = self.register_place(*rhs) else { return }; - self.assignments.insert((lhs, rhs)); - } - Rvalue::Aggregate(kind, fields) => { - let Some(mut lhs) = self.register_place(*lhs) else { return }; - match **kind { - // Do not propagate unions. - AggregateKind::Adt(_, _, _, _, Some(_)) => return, - AggregateKind::Adt(_, variant, _, _, None) => { - let ty = self.map.places[lhs].ty; - if ty.is_enum() { - lhs = self.map.register_place(ty, lhs, TrackElem::Variant(variant)); - } - } - AggregateKind::RawPtr(..) - | AggregateKind::Array(_) - | AggregateKind::Tuple - | AggregateKind::Closure(..) - | AggregateKind::Coroutine(..) - | AggregateKind::CoroutineClosure(..) => {} - } - for (index, field) in fields.iter_enumerated() { - if let Some(rhs) = field.place() - && let Some(rhs) = self.register_place(rhs) - { - let lhs = self.map.register_place( - self.map.places[rhs].ty, - lhs, - TrackElem::Field(index), - ); - self.assignments.insert((lhs, rhs)); - } - } - } - _ => {} - } + self.map.register_place(self.tcx, self.body, *place); } } From ff8d36844cc499757ac580c31511e60ec4b84d43 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 20 Jun 2025 17:41:52 +0000 Subject: [PATCH 4/6] Pre-allocate places vectors. --- compiler/rustc_mir_dataflow/src/value_analysis.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index f7751b5572e40..6297b7008f3e1 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -364,12 +364,13 @@ impl<'tcx> Map<'tcx> { /// chosen is an implementation detail and may not be relied upon (other than that their type /// are scalars). pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { + let capacity = 4 * body.local_decls.len() + value_limit.unwrap_or(body.local_decls.len()); let mut map = Self { locals: IndexVec::from_elem(None, &body.local_decls), projections: FxHashMap::default(), - places: IndexVec::new(), + places: IndexVec::with_capacity(capacity), value_count: 0, - inner_values: IndexVec::new(), + inner_values: IndexVec::with_capacity(capacity), inner_values_buffer: Vec::new(), }; map.register_locals(tcx, body); From c12e371ec8b5e50ca7e1594715069b22c7534936 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 22 Jun 2025 13:51:39 +0000 Subject: [PATCH 5/6] Create place and value indices on-demand. --- .../rustc_mir_dataflow/src/value_analysis.rs | 188 ++++++++++++++---- .../src/dataflow_const_prop.rs | 6 +- .../rustc_mir_transform/src/jump_threading.rs | 88 +++++--- 3 files changed, 210 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 6297b7008f3e1..b7c0b0fc245df 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1,3 +1,4 @@ +use std::assert_matches::debug_assert_matches; use std::fmt::{Debug, Formatter}; use std::ops::Range; @@ -352,32 +353,47 @@ pub struct Map<'tcx> { projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>, places: IndexVec>, value_count: usize, + mode: PlaceCollectionMode, // The Range corresponds to a slice into `inner_values_buffer`. inner_values: IndexVec>, inner_values_buffer: Vec, } +#[derive(Copy, Clone, Debug)] +pub enum PlaceCollectionMode { + Full { value_limit: Option }, + OnDemand, +} + impl<'tcx> Map<'tcx> { /// Returns a map that only tracks places whose type has scalar layout. /// /// This is currently the only way to create a [`Map`]. The way in which the tracked places are /// chosen is an implementation detail and may not be relied upon (other than that their type /// are scalars). - pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) -> Self { - let capacity = 4 * body.local_decls.len() + value_limit.unwrap_or(body.local_decls.len()); + #[tracing::instrument(level = "trace", skip(tcx, body))] + pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, mode: PlaceCollectionMode) -> Self { + tracing::trace!(def_id=?body.source.def_id()); + let capacity = 4 * body.local_decls.len(); let mut map = Self { locals: IndexVec::from_elem(None, &body.local_decls), projections: FxHashMap::default(), places: IndexVec::with_capacity(capacity), value_count: 0, - inner_values: IndexVec::with_capacity(capacity), + mode, + inner_values: IndexVec::new(), inner_values_buffer: Vec::new(), }; map.register_locals(tcx, body); - map.collect_places(tcx, body); - map.propagate_assignments(tcx, body); - map.create_values(tcx, body, value_limit); - map.trim_useless_places(); + match mode { + PlaceCollectionMode::Full { value_limit } => { + map.collect_places(tcx, body); + map.propagate_assignments(tcx, body); + map.create_values(tcx, body, value_limit); + map.trim_useless_places(); + } + PlaceCollectionMode::OnDemand => {} + } debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len()); map } @@ -429,12 +445,18 @@ impl<'tcx> Map<'tcx> { match rhs { Rvalue::Use(Operand::Move(rhs) | Operand::Copy(rhs)) | Rvalue::CopyForDeref(rhs) => { - let Some(lhs) = self.register_place(tcx, body, *lhs) else { continue }; - let Some(rhs) = self.register_place(tcx, body, *rhs) else { continue }; + let Some(lhs) = self.register_place_and_discr(tcx, body, *lhs) else { + continue; + }; + let Some(rhs) = self.register_place_and_discr(tcx, body, *rhs) else { + continue; + }; assignments.insert((lhs, rhs)); } Rvalue::Aggregate(kind, fields) => { - let Some(mut lhs) = self.register_place(tcx, body, *lhs) else { continue }; + let Some(mut lhs) = self.register_place_and_discr(tcx, body, *lhs) else { + continue; + }; match **kind { // Do not propagate unions. AggregateKind::Adt(_, _, _, _, Some(_)) => continue, @@ -457,7 +479,7 @@ impl<'tcx> Map<'tcx> { } for (index, field) in fields.iter_enumerated() { if let Some(rhs) = field.place() - && let Some(rhs) = self.register_place(tcx, body, rhs) + && let Some(rhs) = self.register_place_and_discr(tcx, body, rhs) { let lhs = self.register_place_index( self.places[rhs].ty, @@ -514,6 +536,7 @@ impl<'tcx> Map<'tcx> { /// Create values for places whose type have scalar layout. #[tracing::instrument(level = "trace", skip(self, tcx, body))] fn create_values(&mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, value_limit: Option) { + debug_assert_matches!(self.mode, PlaceCollectionMode::Full { .. }); let typing_env = body.typing_env(tcx); for place_info in self.places.iter_mut() { // The user requires a bound on the number of created values. @@ -552,6 +575,7 @@ impl<'tcx> Map<'tcx> { /// Trim useless places. #[tracing::instrument(level = "trace", skip(self))] fn trim_useless_places(&mut self) { + debug_assert_matches!(self.mode, PlaceCollectionMode::Full { .. }); for opt_place in self.locals.iter_mut() { if let Some(place) = *opt_place && self.inner_values[place].is_empty() @@ -564,7 +588,7 @@ impl<'tcx> Map<'tcx> { } #[tracing::instrument(level = "trace", skip(self), ret)] - fn register_place_index( + pub fn register_place_index( &mut self, ty: Ty<'tcx>, base: PlaceIndex, @@ -578,49 +602,124 @@ impl<'tcx> Map<'tcx> { }) } - #[tracing::instrument(level = "trace", skip(self, tcx, body))] - fn register_place( + #[tracing::instrument(level = "trace", skip(self, tcx, body), ret)] + pub fn register_place( &mut self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>, + tail: Option, ) -> Option { // Create a place for this projection. let mut place_index = self.locals[place.local]?; let mut ty = PlaceTy::from_ty(body.local_decls[place.local].ty); tracing::trace!(?place_index, ?ty); - if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() - && let ty::Slice(..) = ref_ty.kind() - { - self.register_place_index(tcx.types.usize, place_index, TrackElem::DerefLen); - } else if ty.ty.is_enum() { - let discriminant_ty = ty.ty.discriminant_ty(tcx); - self.register_place_index(discriminant_ty, place_index, TrackElem::Discriminant); - } - for proj in place.projection { let track_elem = proj.try_into().ok()?; ty = ty.projection_ty(tcx, proj); place_index = self.register_place_index(ty.ty, place_index, track_elem); tracing::trace!(?proj, ?place_index, ?ty); + } - if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.ty.kind() - && let ty::Slice(..) = ref_ty.kind() - { - self.register_place_index(tcx.types.usize, place_index, TrackElem::DerefLen); - } else if ty.ty.is_enum() { - let discriminant_ty = ty.ty.discriminant_ty(tcx); - self.register_place_index(discriminant_ty, place_index, TrackElem::Discriminant); - } + if let Some(tail) = tail { + let ty = match tail { + TrackElem::Discriminant => ty.ty.discriminant_ty(tcx), + TrackElem::Variant(..) | TrackElem::Field(..) => todo!(), + TrackElem::DerefLen => tcx.types.usize, + }; + place_index = self.register_place_index(ty, place_index, tail); } Some(place_index) } + #[tracing::instrument(level = "trace", skip(self, tcx, body), ret)] + fn register_place_and_discr( + &mut self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + place: Place<'tcx>, + ) -> Option { + let place = self.register_place(tcx, body, place, None)?; + let ty = self.places[place].ty; + + if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind() + && let ty::Slice(..) = ref_ty.kind() + { + self.register_place_index(tcx.types.usize, place, TrackElem::DerefLen); + } else if ty.is_enum() { + let discriminant_ty = ty.discriminant_ty(tcx); + self.register_place_index(discriminant_ty, place, TrackElem::Discriminant); + } + + Some(place) + } + + #[tracing::instrument(level = "trace", skip(self, tcx, typing_env), ret)] + pub fn register_value( + &mut self, + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + place: PlaceIndex, + ) -> Option { + let place_info = &mut self.places[place]; + if let Some(value) = place_info.value_index { + return Some(value); + } + + if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, place_info.ty) { + place_info.ty = ty; + } + + // Allocate a value slot if it doesn't have one, and the user requested one. + if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(place_info.ty)) + && layout.backend_repr.is_scalar() + { + place_info.value_index = Some(self.value_count.into()); + self.value_count += 1; + } + + place_info.value_index + } + + #[tracing::instrument(level = "trace", skip(self, f))] + pub fn register_copy_tree( + &mut self, + // Tree to copy. + source: PlaceIndex, + // Tree to build. + target: PlaceIndex, + f: &mut impl FnMut(ValueIndex, ValueIndex), + ) { + if let Some(source_value) = self.places[source].value_index { + let target_value = *self.places[target].value_index.get_or_insert_with(|| { + let value_index = self.value_count.into(); + self.value_count += 1; + value_index + }); + f(source_value, target_value) + } + + // Iterate over `source` children and recurse. + let mut source_child_iter = self.places[source].first_child; + while let Some(source_child) = source_child_iter { + source_child_iter = self.places[source_child].next_sibling; + + // Try to find corresponding child and recurse. Reasoning is similar as above. + let source_info = &self.places[source_child]; + let source_ty = source_info.ty; + let source_elem = source_info.proj_elem.unwrap(); + let target_child = self.register_place_index(source_ty, target, source_elem); + self.register_copy_tree(source_child, target_child, f); + } + } + /// Precompute the list of values inside `root` and store it inside /// as a slice within `inner_values_buffer`. + #[tracing::instrument(level = "trace", skip(self))] fn cache_preorder_invoke(&mut self, root: PlaceIndex) { + debug_assert_matches!(self.mode, PlaceCollectionMode::Full { .. }); let start = self.inner_values_buffer.len(); if let Some(vi) = self.places[root].value_index { self.inner_values_buffer.push(vi); @@ -651,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> { return; } - self.map.register_place(self.tcx, self.body, *place); + self.map.register_place_and_discr(self.tcx, self.body, *place); } } @@ -726,6 +825,7 @@ impl<'tcx> Map<'tcx> { /// /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track /// as such. + #[tracing::instrument(level = "trace", skip(self, f))] pub fn for_each_aliasing_place( &self, place: PlaceRef<'_>, @@ -763,6 +863,7 @@ impl<'tcx> Map<'tcx> { } /// Invoke the given function on all the descendants of the given place, except one branch. + #[tracing::instrument(level = "trace", skip(self, f))] fn for_each_variant_sibling( &self, parent: PlaceIndex, @@ -783,11 +884,22 @@ impl<'tcx> Map<'tcx> { } /// Invoke a function on each value in the given place and all descendants. + #[tracing::instrument(level = "trace", skip(self, f))] fn for_each_value_inside(&self, root: PlaceIndex, f: &mut impl FnMut(ValueIndex)) { - let range = self.inner_values[root].clone(); - let values = &self.inner_values_buffer[range]; - for &v in values { - f(v) + if let Some(range) = self.inner_values.get(root) { + // Optimized path: we have cached the inner values. + let values = &self.inner_values_buffer[range.clone()]; + for &v in values { + f(v) + } + } else { + if let Some(root) = self.places[root].value_index { + f(root) + } + + for child in self.children(root) { + self.for_each_value_inside(child, f); + } } } @@ -800,7 +912,9 @@ impl<'tcx> Map<'tcx> { f: &mut impl FnMut(PlaceIndex, &O), ) { // Fast path is there is nothing to do. - if self.inner_values[root].is_empty() { + if let Some(value_range) = self.inner_values.get(root) + && value_range.is_empty() + { return; } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 0cf8142a560fb..7434aaecb40f5 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; use rustc_mir_dataflow::value_analysis::{ - Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, + Map, PlaceCollectionMode, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, }; use rustc_mir_dataflow::{Analysis, ResultsVisitor, visit_reachable_results}; use rustc_span::DUMMY_SP; @@ -55,10 +55,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { // `O(num_nodes * tracked_places * n)` in terms of time complexity. Since the number of // map nodes is strongly correlated to the number of tracked places, this becomes more or // less `O(n)` if we place a constant limit on the number of tracked places. - let place_limit = if tcx.sess.mir_opt_level() < 4 { Some(PLACE_LIMIT) } else { None }; + let value_limit = if tcx.sess.mir_opt_level() < 4 { Some(PLACE_LIMIT) } else { None }; // Decide which places to track during the analysis. - let map = Map::new(tcx, body, place_limit); + let map = Map::new(tcx, body, PlaceCollectionMode::Full { value_limit }); // Perform the actual dataflow analysis. let mut const_ = debug_span!("analyze") diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 54d5dbb655bb1..0f5959d828344 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -48,7 +48,9 @@ use rustc_middle::mir::*; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; use rustc_mir_dataflow::lattice::HasBottom; -use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, TrackElem, ValueIndex}; +use rustc_mir_dataflow::value_analysis::{ + Map, PlaceCollectionMode, PlaceIndex, TrackElem, ValueIndex, +}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; @@ -58,7 +60,6 @@ pub(super) struct JumpThreading; const MAX_BACKTRACK: usize = 5; const MAX_COST: usize = 100; -const MAX_PLACES: usize = 100; impl<'tcx> crate::MirPass<'tcx> for JumpThreading { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { @@ -84,7 +85,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), body, arena, - map: Map::new(tcx, body, Some(MAX_PLACES)), + map: Map::new(tcx, body, PlaceCollectionMode::OnDemand), loop_headers: loop_headers(body), opportunities: Vec::new(), }; @@ -215,6 +216,19 @@ impl<'a> ConditionSet<'a> { } impl<'a, 'tcx> TOFinder<'a, 'tcx> { + fn place(&mut self, place: Place<'tcx>, tail: Option) -> Option { + self.map.register_place(self.tcx, self.body, place, tail) + } + + fn value(&mut self, place: PlaceIndex) -> Option { + self.map.register_value(self.tcx, self.typing_env, place) + } + + fn place_value(&mut self, place: Place<'tcx>, tail: Option) -> Option { + let place = self.place(place, tail)?; + self.value(place) + } + /// Recursion entry point to find threading opportunities. #[instrument(level = "trace", skip(self))] fn start_from_switch(&mut self, bb: BasicBlock) { @@ -229,7 +243,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let discr_ty = discr.ty(self.body, self.tcx).ty; let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; - let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; + let Some(discr) = self.place_value(discr, None) else { return }; debug!(?discr); let cost = CostChecker::new(self.tcx, self.typing_env, None, self.body); @@ -405,7 +419,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { rhs: ImmTy<'tcx>, state: &mut ConditionSet<'a>, ) { - if let Some(lhs) = self.map.value(lhs) + if let Some(lhs) = self.value(lhs) && let Immediate::Scalar(Scalar::Int(int)) = *rhs { state.register_matches(lhs, int, Some(bb), &mut self.opportunities); @@ -455,9 +469,13 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { #[instrument(level = "trace", skip(self))] fn process_copy(&mut self, lhs: PlaceIndex, rhs: PlaceIndex, state: &mut ConditionSet<'a>) { let mut renames = FxHashMap::default(); - self.map.for_each_value_pair(rhs, lhs, &mut |rhs, lhs| { - renames.insert(lhs, rhs); - }); + self.map.register_copy_tree( + lhs, // tree to copy + rhs, // tree to build + &mut |lhs, rhs| { + renames.insert(lhs, rhs); + }, + ); *state = state.map(self.arena, |mut c| { if let Some(rhs) = renames.get(&c.place) { c.place = *rhs @@ -486,7 +504,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } // Transfer the conditions on the copied rhs. Operand::Move(rhs) | Operand::Copy(rhs) => { - let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; + let Some(rhs) = self.place(*rhs, None) else { return }; self.process_copy(lhs, rhs, state) } } @@ -500,16 +518,16 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { rvalue: &Rvalue<'tcx>, state: &mut ConditionSet<'a>, ) { - let Some(lhs) = self.map.find(lhs_place.as_ref()) else { return }; + let Some(lhs) = self.place(*lhs_place, None) else { return }; match rvalue { Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), // Transfer the conditions on the copy rhs. Rvalue::CopyForDeref(rhs) => { - let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; + let Some(rhs) = self.place(*rhs, None) else { return }; self.process_copy(lhs, rhs, state) } Rvalue::Discriminant(rhs) => { - let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; + let Some(rhs) = self.place(*rhs, Some(TrackElem::Discriminant)) else { return }; self.process_copy(lhs, rhs, state) } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. @@ -519,33 +537,37 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Do not support unions. AggregateKind::Adt(.., Some(_)) => return, AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { - if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant) - && let Some(discr_value) = self - .ecx - .discriminant_for_variant(agg_ty, *variant_index) - .discard_err() + let discr_ty = agg_ty.discriminant_ty(self.tcx); + let discr_target = + self.map.register_place_index(discr_ty, lhs, TrackElem::Discriminant); + if let Some(discr_value) = + self.ecx.discriminant_for_variant(agg_ty, *variant_index).discard_err() { self.process_immediate(bb, discr_target, discr_value, state); } - if let Some(idx) = self.map.apply(lhs, TrackElem::Variant(*variant_index)) { - idx - } else { - return; - } + self.map.register_place_index( + agg_ty, + lhs, + TrackElem::Variant(*variant_index), + ) } _ => lhs, }; for (field_index, operand) in operands.iter_enumerated() { - if let Some(field) = self.map.apply(lhs, TrackElem::Field(field_index)) { - self.process_operand(bb, field, operand, state); - } + let operand_ty = operand.ty(self.body, self.tcx); + let field = self.map.register_place_index( + operand_ty, + lhs, + TrackElem::Field(field_index), + ); + self.process_operand(bb, field, operand, state); } } // Transfer the conditions on the copy rhs, after inverting the value of the condition. Rvalue::UnaryOp(UnOp::Not, Operand::Move(operand) | Operand::Copy(operand)) => { let layout = self.ecx.layout_of(operand.ty(self.body, self.tcx).ty).unwrap(); - let Some(lhs) = self.map.value(lhs) else { return }; - let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; + let Some(lhs) = self.value(lhs) else { return }; + let Some(operand) = self.place_value(*operand, None) else { return }; *state = state.filter_map(self.arena, |mut cond| { if cond.place == lhs { cond.place = operand; @@ -578,8 +600,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Avoid handling them, though this could be extended in the future. return; } - let Some(lhs) = self.map.value(lhs) else { return }; - let Some(operand) = self.map.find_value(operand.as_ref()) else { return }; + let Some(lhs) = self.value(lhs) else { return }; + let Some(operand) = self.place_value(*operand, None) else { return }; let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.typing_env) else { return; @@ -620,7 +642,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // If we expect `discriminant(place) ?= A`, // we have an opportunity if `variant_index ?= A`. StatementKind::SetDiscriminant { box place, variant_index } => { - let Some(discr_target) = self.map.find_discr(place.as_ref()) else { return }; + let Some(discr_target) = self.place(*place, Some(TrackElem::Discriminant)) else { + return; + }; let enum_ty = place.ty(self.body, self.tcx).ty; // `SetDiscriminant` guarantees that the discriminant is now `variant_index`. // Even if the discriminant write does nothing due to niches, it is UB to set the @@ -636,7 +660,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume( Operand::Copy(place) | Operand::Move(place), )) => { - let Some(place) = self.map.find_value(place.as_ref()) else { return }; + let Some(place) = self.place_value(*place, None) else { return }; state.register_matches(place, ScalarInt::TRUE, Some(bb), &mut self.opportunities) } StatementKind::Assign(box (lhs_place, rhs)) => { @@ -703,7 +727,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return; }; - let Some(discr) = self.map.find_value(discr.as_ref()) else { return }; + let Some(discr) = self.place_value(discr, None) else { return }; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { let Some(value) = ScalarInt::try_from_uint(value, discr_layout.size) else { return }; From b3f7763e4b42054cbc6ad614233b578e3348ea89 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 Jun 2025 17:21:28 +0000 Subject: [PATCH 6/6] Bless coverage. --- tests/coverage/closure.cov-map | 56 +++--- tests/coverage/conditions.cov-map | 254 +++++++++++------------- tests/coverage/try_error_result.cov-map | 229 +++++++++------------ 3 files changed, 232 insertions(+), 307 deletions(-) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 5f7e4ce58e97b..fcfa1dfc5be90 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -74,24 +74,22 @@ Number of file 0 mappings: 66 - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 -Function name: closure::main::{closure#0} -Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 28, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 17, 01, 00, 18, 00, 20, 01, 01, 05, 00, 06] +Function name: closure::main::{closure#0} (unused) +Raw bytes (49): 0x[01, 01, 00, 09, 00, 28, 05, 00, 06, 00, 01, 0d, 00, 1a, 00, 00, 1d, 00, 1e, 00, 01, 0c, 00, 14, 00, 00, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 00, 17, 00, 00, 18, 00, 20, 00, 01, 05, 00, 06] Number of files: 1 - file 0 => $DIR/closure.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 40, 5) to (start + 0, 6) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) -- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) -- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 23) -- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 32) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) -Highest counter ID seen: c1 +- Code(Zero) at (prev + 40, 5) to (start + 0, 6) +- Code(Zero) at (prev + 1, 13) to (start + 0, 26) +- Code(Zero) at (prev + 0, 29) to (start + 0, 30) +- Code(Zero) at (prev + 1, 12) to (start + 0, 20) +- Code(Zero) at (prev + 0, 21) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 9) to (start + 0, 23) +- Code(Zero) at (prev + 0, 24) to (start + 0, 32) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +Highest counter ID seen: (none) Function name: closure::main::{closure#10} (unused) Raw bytes (25): 0x[01, 01, 00, 04, 00, 9b, 01, 07, 00, 08, 00, 00, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 00, 20, 00, 21] @@ -197,24 +195,22 @@ Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 -Function name: closure::main::{closure#18} -Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 19, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] +Function name: closure::main::{closure#18} (unused) +Raw bytes (49): 0x[01, 01, 00, 09, 00, 19, 0d, 00, 0e, 00, 01, 15, 00, 22, 00, 00, 25, 00, 26, 00, 01, 14, 00, 1c, 00, 00, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 00, 1f, 00, 00, 20, 00, 28, 00, 01, 0d, 00, 0e] Number of files: 1 - file 0 => $DIR/closure.rs -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 25, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 34) -- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 38) -- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 28) -- Code(Counter(1)) at (prev + 0, 29) to (start + 2, 18) -- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 31) -- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 40) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -Highest counter ID seen: c1 +- Code(Zero) at (prev + 25, 13) to (start + 0, 14) +- Code(Zero) at (prev + 1, 21) to (start + 0, 34) +- Code(Zero) at (prev + 0, 37) to (start + 0, 38) +- Code(Zero) at (prev + 1, 20) to (start + 0, 28) +- Code(Zero) at (prev + 0, 29) to (start + 2, 18) +- Code(Zero) at (prev + 2, 17) to (start + 0, 18) +- Code(Zero) at (prev + 1, 17) to (start + 0, 31) +- Code(Zero) at (prev + 0, 32) to (start + 0, 40) +- Code(Zero) at (prev + 1, 13) to (start + 0, 14) +Highest counter ID seen: (none) Function name: closure::main::{closure#19} Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 43, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 29d9604085ede..0047d52c89fab 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,95 +1,75 @@ Function name: conditions::main -Raw bytes (656): 0x[01, 01, 57, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 9f, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 9f, 01, 15, 0d, 11, 19, 45, 19, 97, 01, 45, 49, 97, 01, 4d, 45, 49, 19, 93, 01, 97, 01, 4d, 45, 49, 9f, 01, 9b, 02, 0d, 11, 15, 19, 15, 19, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, 9b, 02, 1d, 15, 19, 21, 39, 21, e3, 01, 39, 3d, e3, 01, 41, 39, 3d, 21, df, 01, e3, 01, 41, 39, 3d, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, d7, 02, 25, 1d, 21, 29, 2d, 29, cf, 02, 2d, 31, cf, 02, 35, 2d, 31, 29, cb, 02, cf, 02, 35, 2d, 31, d7, 02, db, 02, 1d, 21, 25, 29, 53, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0c, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 00, 17, 05, 01, 09, 00, 0a, 06, 01, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 00, 17, 09, 01, 09, 00, 12, 2a, 02, 09, 00, 0f, 03, 03, 09, 00, 16, 03, 00, 19, 00, 1a, 03, 01, 08, 00, 0c, 03, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 9f, 01, 03, 08, 00, 0c, 9f, 01, 01, 0d, 00, 1a, 9f, 01, 00, 1d, 00, 1e, 9f, 01, 01, 0c, 00, 10, 9f, 01, 00, 11, 02, 0a, 00, 02, 09, 00, 0a, 9f, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 72, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 7a, 00, 21, 00, 2e, 7e, 00, 32, 00, 40, 93, 01, 00, 41, 02, 0e, 8e, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 9a, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, 9b, 02, 02, 09, 00, 16, 9b, 02, 00, 19, 00, 1a, 9b, 02, 01, 08, 00, 0c, 9b, 02, 00, 0d, 02, 06, 00, 02, 05, 00, 06, d7, 02, 02, 09, 00, 0a, 9b, 02, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, be, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, c6, 01, 00, 1d, 00, 2a, ca, 01, 00, 2e, 00, 3c, df, 01, 00, 3d, 02, 0a, da, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, 96, 02, 02, 0d, 00, 20, 96, 02, 00, 23, 00, 2c, 96, 02, 01, 09, 00, 11, 96, 02, 00, 12, 00, 1b, 96, 02, 01, 09, 00, 0f, db, 02, 03, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, aa, 02, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, b2, 02, 00, 1d, 00, 2a, b6, 02, 00, 2e, 00, 3c, cb, 02, 00, 3d, 02, 0a, c6, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, d2, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (595): 0x[01, 01, 43, 05, 09, 01, 05, 09, 51, 09, 13, 51, 55, 01, 03, 03, 0d, 11, 49, 11, 27, 49, 4d, 03, 63, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 63, 15, 0d, 11, 19, 41, 19, 5b, 41, 45, 63, cb, 01, 0d, 11, 15, 19, 15, 19, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, cb, 01, 1d, 15, 19, 21, 39, 21, 93, 01, 39, 3d, cb, 01, 87, 02, 15, 19, 1d, 21, cb, 01, 87, 02, 15, 19, 1d, 21, cb, 01, 87, 02, 15, 19, 1d, 21, cb, 01, 87, 02, 15, 19, 1d, 21, cb, 01, 87, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, 87, 02, 25, 1d, 21, 29, 2d, 29, ff, 01, 2d, 31, ff, 01, 35, 2d, 31, 29, fb, 01, ff, 01, 35, 2d, 31, 87, 02, 8b, 02, 1d, 21, 25, 29, 53, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0c, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 00, 17, 05, 01, 09, 00, 0a, 06, 01, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 09, 00, 3d, 02, 0a, 00, 02, 09, 00, 0a, 09, 01, 09, 00, 17, 09, 01, 09, 00, 12, 16, 02, 09, 00, 0f, 03, 03, 09, 00, 16, 03, 00, 19, 00, 1a, 03, 01, 08, 00, 0c, 03, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 11, 00, 3d, 02, 0a, 00, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 2a, 02, 09, 00, 0f, 63, 03, 08, 00, 0c, 63, 01, 0d, 00, 1a, 63, 00, 1d, 00, 1e, 63, 01, 0c, 00, 10, 63, 00, 11, 02, 0a, 00, 02, 09, 00, 0a, 63, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 4a, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 52, 00, 21, 00, 2e, 56, 00, 32, 00, 40, 19, 00, 41, 02, 0e, 00, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 5e, 02, 0d, 00, 13, 00, 02, 05, 00, 06, cb, 01, 02, 09, 00, 16, cb, 01, 00, 19, 00, 1a, cb, 01, 01, 08, 00, 0c, cb, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 87, 02, 02, 09, 00, 0a, cb, 01, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, 82, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, 8a, 01, 00, 1d, 00, 2a, 8e, 01, 00, 2e, 00, 3c, 21, 00, 3d, 02, 0a, 00, 02, 09, 00, 0a, 21, 01, 09, 00, 17, c6, 01, 02, 0d, 00, 20, c6, 01, 00, 23, 00, 2c, c6, 01, 01, 09, 00, 11, c6, 01, 00, 12, 00, 1b, c6, 01, 01, 09, 00, 0f, 8b, 02, 03, 09, 00, 0a, 87, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, da, 01, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, e2, 01, 00, 1d, 00, 2a, e6, 01, 00, 2e, 00, 3c, fb, 01, 00, 3d, 02, 0a, f6, 01, 02, 09, 00, 0a, 29, 01, 09, 00, 17, 82, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => $DIR/conditions.rs -Number of expressions: 87 +Number of expressions: 67 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Counter(1) -- expression 2 operands: lhs = Counter(2), rhs = Counter(23) -- expression 3 operands: lhs = Counter(2), rhs = Expression(9, Add) -- expression 4 operands: lhs = Counter(23), rhs = Counter(24) -- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(25) -- expression 6 operands: lhs = Counter(23), rhs = Counter(24) -- expression 7 operands: lhs = Counter(2), rhs = Expression(8, Add) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(25) -- expression 9 operands: lhs = Counter(23), rhs = Counter(24) -- expression 10 operands: lhs = Counter(0), rhs = Expression(0, Add) -- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 12 operands: lhs = Counter(4), rhs = Counter(20) -- expression 13 operands: lhs = Counter(4), rhs = Expression(19, Add) -- expression 14 operands: lhs = Counter(20), rhs = Counter(21) -- expression 15 operands: lhs = Expression(19, Add), rhs = Counter(22) -- expression 16 operands: lhs = Counter(20), rhs = Counter(21) -- expression 17 operands: lhs = Counter(4), rhs = Expression(18, Add) -- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(22) -- expression 19 operands: lhs = Counter(20), rhs = Counter(21) -- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(39, Add) -- expression 21 operands: lhs = Counter(3), rhs = Counter(4) -- expression 22 operands: lhs = Counter(3), rhs = Counter(4) -- expression 23 operands: lhs = Counter(3), rhs = Counter(4) +- expression 2 operands: lhs = Counter(2), rhs = Counter(20) +- expression 3 operands: lhs = Counter(2), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(20), rhs = Counter(21) +- expression 5 operands: lhs = Counter(0), rhs = Expression(0, Add) +- expression 6 operands: lhs = Expression(0, Add), rhs = Counter(3) +- expression 7 operands: lhs = Counter(4), rhs = Counter(18) +- expression 8 operands: lhs = Counter(4), rhs = Expression(9, Add) +- expression 9 operands: lhs = Counter(18), rhs = Counter(19) +- expression 10 operands: lhs = Expression(0, Add), rhs = Expression(24, Add) +- expression 11 operands: lhs = Counter(3), rhs = Counter(4) +- expression 12 operands: lhs = Counter(3), rhs = Counter(4) +- expression 13 operands: lhs = Counter(3), rhs = Counter(4) +- expression 14 operands: lhs = Counter(3), rhs = Counter(4) +- expression 15 operands: lhs = Counter(3), rhs = Counter(4) +- expression 16 operands: lhs = Counter(3), rhs = Counter(4) +- expression 17 operands: lhs = Counter(3), rhs = Counter(4) +- expression 18 operands: lhs = Expression(24, Add), rhs = Counter(5) +- expression 19 operands: lhs = Counter(3), rhs = Counter(4) +- expression 20 operands: lhs = Counter(6), rhs = Counter(16) +- expression 21 operands: lhs = Counter(6), rhs = Expression(22, Add) +- expression 22 operands: lhs = Counter(16), rhs = Counter(17) +- expression 23 operands: lhs = Expression(24, Add), rhs = Expression(50, Add) - expression 24 operands: lhs = Counter(3), rhs = Counter(4) -- expression 25 operands: lhs = Counter(3), rhs = Counter(4) -- expression 26 operands: lhs = Counter(3), rhs = Counter(4) -- expression 27 operands: lhs = Counter(3), rhs = Counter(4) -- expression 28 operands: lhs = Expression(39, Add), rhs = Counter(5) -- expression 29 operands: lhs = Counter(3), rhs = Counter(4) -- expression 30 operands: lhs = Counter(6), rhs = Counter(17) -- expression 31 operands: lhs = Counter(6), rhs = Expression(37, Add) -- expression 32 operands: lhs = Counter(17), rhs = Counter(18) -- expression 33 operands: lhs = Expression(37, Add), rhs = Counter(19) -- expression 34 operands: lhs = Counter(17), rhs = Counter(18) -- expression 35 operands: lhs = Counter(6), rhs = Expression(36, Add) -- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(19) -- expression 37 operands: lhs = Counter(17), rhs = Counter(18) -- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(70, Add) -- expression 39 operands: lhs = Counter(3), rhs = Counter(4) -- expression 40 operands: lhs = Counter(5), rhs = Counter(6) +- expression 25 operands: lhs = Counter(5), rhs = Counter(6) +- expression 26 operands: lhs = Counter(5), rhs = Counter(6) +- expression 27 operands: lhs = Counter(5), rhs = Counter(6) +- expression 28 operands: lhs = Counter(5), rhs = Counter(6) +- expression 29 operands: lhs = Counter(5), rhs = Counter(6) +- expression 30 operands: lhs = Counter(7), rhs = Counter(8) +- expression 31 operands: lhs = Counter(5), rhs = Counter(6) +- expression 32 operands: lhs = Expression(50, Add), rhs = Counter(7) +- expression 33 operands: lhs = Counter(5), rhs = Counter(6) +- expression 34 operands: lhs = Counter(8), rhs = Counter(14) +- expression 35 operands: lhs = Counter(8), rhs = Expression(36, Add) +- expression 36 operands: lhs = Counter(14), rhs = Counter(15) +- expression 37 operands: lhs = Expression(50, Add), rhs = Expression(65, Add) +- expression 38 operands: lhs = Counter(5), rhs = Counter(6) +- expression 39 operands: lhs = Counter(7), rhs = Counter(8) +- expression 40 operands: lhs = Expression(50, Add), rhs = Expression(65, Add) - expression 41 operands: lhs = Counter(5), rhs = Counter(6) -- expression 42 operands: lhs = Counter(5), rhs = Counter(6) -- expression 43 operands: lhs = Counter(5), rhs = Counter(6) +- expression 42 operands: lhs = Counter(7), rhs = Counter(8) +- expression 43 operands: lhs = Expression(50, Add), rhs = Expression(65, Add) - expression 44 operands: lhs = Counter(5), rhs = Counter(6) - expression 45 operands: lhs = Counter(7), rhs = Counter(8) -- expression 46 operands: lhs = Counter(5), rhs = Counter(6) -- expression 47 operands: lhs = Expression(70, Add), rhs = Counter(7) -- expression 48 operands: lhs = Counter(5), rhs = Counter(6) -- expression 49 operands: lhs = Counter(8), rhs = Counter(14) -- expression 50 operands: lhs = Counter(8), rhs = Expression(56, Add) -- expression 51 operands: lhs = Counter(14), rhs = Counter(15) -- expression 52 operands: lhs = Expression(56, Add), rhs = Counter(16) -- expression 53 operands: lhs = Counter(14), rhs = Counter(15) -- expression 54 operands: lhs = Counter(8), rhs = Expression(55, Add) -- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(16) -- expression 56 operands: lhs = Counter(14), rhs = Counter(15) -- expression 57 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) -- expression 58 operands: lhs = Counter(5), rhs = Counter(6) -- expression 59 operands: lhs = Counter(7), rhs = Counter(8) -- expression 60 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) -- expression 61 operands: lhs = Counter(5), rhs = Counter(6) -- expression 62 operands: lhs = Counter(7), rhs = Counter(8) -- expression 63 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) -- expression 64 operands: lhs = Counter(5), rhs = Counter(6) +- expression 46 operands: lhs = Expression(50, Add), rhs = Expression(65, Add) +- expression 47 operands: lhs = Counter(5), rhs = Counter(6) +- expression 48 operands: lhs = Counter(7), rhs = Counter(8) +- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(65, Add) +- expression 50 operands: lhs = Counter(5), rhs = Counter(6) +- expression 51 operands: lhs = Counter(7), rhs = Counter(8) +- expression 52 operands: lhs = Counter(9), rhs = Counter(10) +- expression 53 operands: lhs = Counter(7), rhs = Counter(8) +- expression 54 operands: lhs = Expression(65, Add), rhs = Counter(9) +- expression 55 operands: lhs = Counter(7), rhs = Counter(8) +- expression 56 operands: lhs = Counter(10), rhs = Counter(11) +- expression 57 operands: lhs = Counter(10), rhs = Expression(63, Add) +- expression 58 operands: lhs = Counter(11), rhs = Counter(12) +- expression 59 operands: lhs = Expression(63, Add), rhs = Counter(13) +- expression 60 operands: lhs = Counter(11), rhs = Counter(12) +- expression 61 operands: lhs = Counter(10), rhs = Expression(62, Add) +- expression 62 operands: lhs = Expression(63, Add), rhs = Counter(13) +- expression 63 operands: lhs = Counter(11), rhs = Counter(12) +- expression 64 operands: lhs = Expression(65, Add), rhs = Expression(66, Add) - expression 65 operands: lhs = Counter(7), rhs = Counter(8) -- expression 66 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) -- expression 67 operands: lhs = Counter(5), rhs = Counter(6) -- expression 68 operands: lhs = Counter(7), rhs = Counter(8) -- expression 69 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) -- expression 70 operands: lhs = Counter(5), rhs = Counter(6) -- expression 71 operands: lhs = Counter(7), rhs = Counter(8) -- expression 72 operands: lhs = Counter(9), rhs = Counter(10) -- expression 73 operands: lhs = Counter(7), rhs = Counter(8) -- expression 74 operands: lhs = Expression(85, Add), rhs = Counter(9) -- expression 75 operands: lhs = Counter(7), rhs = Counter(8) -- expression 76 operands: lhs = Counter(10), rhs = Counter(11) -- expression 77 operands: lhs = Counter(10), rhs = Expression(83, Add) -- expression 78 operands: lhs = Counter(11), rhs = Counter(12) -- expression 79 operands: lhs = Expression(83, Add), rhs = Counter(13) -- expression 80 operands: lhs = Counter(11), rhs = Counter(12) -- expression 81 operands: lhs = Counter(10), rhs = Expression(82, Add) -- expression 82 operands: lhs = Expression(83, Add), rhs = Counter(13) -- expression 83 operands: lhs = Counter(11), rhs = Counter(12) -- expression 84 operands: lhs = Expression(85, Add), rhs = Expression(86, Add) -- expression 85 operands: lhs = Counter(7), rhs = Counter(8) -- expression 86 operands: lhs = Counter(9), rhs = Counter(10) +- expression 66 operands: lhs = Counter(9), rhs = Counter(10) Number of file 0 mappings: 83 - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) @@ -106,16 +86,14 @@ Number of file 0 mappings: 83 = (c0 - c1) - Code(Counter(2)) at (prev + 1, 12) to (start + 0, 25) - Code(Expression(2, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (c2 - c23) + = (c2 - c20) - Code(Expression(3, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (c2 - (c23 + c24)) -- Code(Expression(8, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c23 + c24) + c25) -- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c2 - ((c23 + c24) + c25)) + = (c2 - (c20 + c21)) +- Code(Counter(2)) at (prev + 0, 61) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 23) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 18) -- Code(Expression(10, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(5, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - (c1 + c2)) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 22) = (c1 + c2) @@ -129,103 +107,97 @@ Number of file 0 mappings: 83 - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) = (c1 + c2) - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6) -- Code(Expression(11, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(6, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c1 + c2) - c3) - Code(Counter(4)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(12, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (c4 - c20) -- Code(Expression(13, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (c4 - (c20 + c21)) -- Code(Expression(18, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c20 + c21) + c22) -- Code(Expression(17, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c4 - ((c20 + c21) + c22)) +- Code(Expression(7, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c4 - c18) +- Code(Expression(8, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (c4 - (c18 + c19)) +- Code(Counter(4)) at (prev + 0, 61) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(4)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(10, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c1 + c2) - (c3 + c4)) -- Code(Expression(39, Add)) at (prev + 3, 8) to (start + 0, 12) +- Code(Expression(24, Add)) at (prev + 3, 8) to (start + 0, 12) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 1, 13) to (start + 0, 26) +- Code(Expression(24, Add)) at (prev + 1, 13) to (start + 0, 26) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 0, 29) to (start + 0, 30) +- Code(Expression(24, Add)) at (prev + 0, 29) to (start + 0, 30) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 1, 12) to (start + 0, 16) +- Code(Expression(24, Add)) at (prev + 1, 12) to (start + 0, 16) = (c3 + c4) -- Code(Expression(39, Add)) at (prev + 0, 17) to (start + 2, 10) +- Code(Expression(24, Add)) at (prev + 0, 17) to (start + 2, 10) = (c3 + c4) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(39, Add)) at (prev + 2, 12) to (start + 0, 25) +- Code(Expression(24, Add)) at (prev + 2, 12) to (start + 0, 25) = (c3 + c4) - Code(Counter(5)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(28, Sub)) at (prev + 4, 17) to (start + 0, 30) +- Code(Expression(18, Sub)) at (prev + 4, 17) to (start + 0, 30) = ((c3 + c4) - c5) - Code(Counter(6)) at (prev + 1, 16) to (start + 0, 29) -- Code(Expression(30, Sub)) at (prev + 0, 33) to (start + 0, 46) - = (c6 - c17) -- Code(Expression(31, Sub)) at (prev + 0, 50) to (start + 0, 64) - = (c6 - (c17 + c18)) -- Code(Expression(36, Add)) at (prev + 0, 65) to (start + 2, 14) - = ((c17 + c18) + c19) -- Code(Expression(35, Sub)) at (prev + 2, 13) to (start + 0, 14) - = (c6 - ((c17 + c18) + c19)) +- Code(Expression(20, Sub)) at (prev + 0, 33) to (start + 0, 46) + = (c6 - c16) +- Code(Expression(21, Sub)) at (prev + 0, 50) to (start + 0, 64) + = (c6 - (c16 + c17)) +- Code(Counter(6)) at (prev + 0, 65) to (start + 2, 14) +- Code(Zero) at (prev + 2, 13) to (start + 0, 14) - Code(Counter(6)) at (prev + 1, 13) to (start + 0, 27) -- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 19) +- Code(Expression(23, Sub)) at (prev + 2, 13) to (start + 0, 19) = ((c3 + c4) - (c5 + c6)) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(70, Add)) at (prev + 2, 9) to (start + 0, 22) +- Code(Expression(50, Add)) at (prev + 2, 9) to (start + 0, 22) = (c5 + c6) -- Code(Expression(70, Add)) at (prev + 0, 25) to (start + 0, 26) +- Code(Expression(50, Add)) at (prev + 0, 25) to (start + 0, 26) = (c5 + c6) -- Code(Expression(70, Add)) at (prev + 1, 8) to (start + 0, 12) +- Code(Expression(50, Add)) at (prev + 1, 8) to (start + 0, 12) = (c5 + c6) -- Code(Expression(70, Add)) at (prev + 0, 13) to (start + 2, 6) +- Code(Expression(50, Add)) at (prev + 0, 13) to (start + 2, 6) = (c5 + c6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(85, Add)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(65, Add)) at (prev + 2, 9) to (start + 0, 10) = (c7 + c8) -- Code(Expression(70, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(50, Add)) at (prev + 0, 16) to (start + 0, 29) = (c5 + c6) - Code(Counter(7)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(47, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(32, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c5 + c6) - c7) - Code(Counter(8)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(49, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(34, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c8 - c14) -- Code(Expression(50, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(35, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c8 - (c14 + c15)) -- Code(Expression(55, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c14 + c15) + c16) -- Code(Expression(54, Sub)) at (prev + 2, 9) to (start + 0, 10) - = (c8 - ((c14 + c15) + c16)) +- Code(Counter(8)) at (prev + 0, 61) to (start + 2, 10) +- Code(Zero) at (prev + 2, 9) to (start + 0, 10) - Code(Counter(8)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(69, Sub)) at (prev + 2, 13) to (start + 0, 32) +- Code(Expression(49, Sub)) at (prev + 2, 13) to (start + 0, 32) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(69, Sub)) at (prev + 0, 35) to (start + 0, 44) +- Code(Expression(49, Sub)) at (prev + 0, 35) to (start + 0, 44) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(69, Sub)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(49, Sub)) at (prev + 1, 9) to (start + 0, 17) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(69, Sub)) at (prev + 0, 18) to (start + 0, 27) +- Code(Expression(49, Sub)) at (prev + 0, 18) to (start + 0, 27) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(69, Sub)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(49, Sub)) at (prev + 1, 9) to (start + 0, 15) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(86, Add)) at (prev + 3, 9) to (start + 0, 10) +- Code(Expression(66, Add)) at (prev + 3, 9) to (start + 0, 10) = (c9 + c10) -- Code(Expression(85, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(65, Add)) at (prev + 0, 16) to (start + 0, 29) = (c7 + c8) - Code(Counter(9)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(74, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(54, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c7 + c8) - c9) - Code(Counter(10)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(76, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(56, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c10 - c11) -- Code(Expression(77, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(57, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c10 - (c11 + c12)) -- Code(Expression(82, Add)) at (prev + 0, 61) to (start + 2, 10) +- Code(Expression(62, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c11 + c12) + c13) -- Code(Expression(81, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(61, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c10 - ((c11 + c12) + c13)) - Code(Counter(10)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(84, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(64, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c7 + c8) - (c9 + c10)) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c10 diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index e08f429615328..8d9431f0b7c8d 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -92,71 +92,28 @@ Number of file 0 mappings: 14 Highest counter ID seen: c2 Function name: try_error_result::test2 -Raw bytes (443): 0x[01, 01, 3d, 0d, 11, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 4f, 53, 1d, 57, 19, 11, 15, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 53, 57, 19, 11, 15, 0d, 4f, 53, 1d, 57, 19, 11, 15, 41, 6b, 21, 25, 41, 21, 41, 6b, 21, 25, 09, 8f, 01, 93, 01, 2d, 0d, 29, 09, 0d, 09, 0d, 09, 93, 01, 0d, 29, 09, 8f, 01, 93, 01, 2d, 0d, 29, 45, a7, 01, 31, 35, 45, 31, 45, a7, 01, 31, 35, 49, bb, 01, 39, 3d, 49, 39, 49, bb, 01, 39, 3d, 05, 09, c7, 01, 09, cb, 01, 3d, cf, 01, 39, d3, 01, 35, d7, 01, 31, db, 01, 2d, df, 01, 29, e3, 01, 25, e7, 01, 21, eb, 01, 1d, ef, 01, 19, f3, 01, 15, 05, 11, 39, 01, 3d, 01, 00, 1d, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 1a, 01, 01, 09, 01, 12, 01, 01, 15, 00, 17, 05, 05, 09, 00, 0e, 09, 02, 09, 01, 11, 09, 04, 0d, 00, 1a, 0d, 02, 0d, 00, 13, 0d, 00, 14, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 00, 35, 02, 00, 45, 00, 4f, 02, 00, 50, 00, 62, 02, 01, 0d, 00, 13, 02, 02, 11, 00, 1c, 15, 01, 11, 00, 12, 36, 02, 11, 00, 15, 36, 02, 11, 00, 1b, 36, 01, 15, 00, 27, 4a, 02, 11, 00, 14, 36, 00, 17, 00, 1d, 36, 00, 1e, 00, 29, 19, 00, 41, 00, 42, 3e, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 4a, 01, 0d, 00, 17, 66, 01, 11, 00, 14, 41, 00, 17, 00, 1d, 41, 00, 1e, 00, 29, 21, 00, 41, 00, 42, 62, 00, 43, 00, 47, 25, 00, 60, 00, 61, 66, 01, 0d, 00, 17, 8a, 01, 04, 11, 00, 14, 7e, 00, 17, 00, 1d, 7e, 00, 1e, 00, 29, 29, 00, 42, 00, 43, 82, 01, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 8a, 01, 01, 0d, 00, 17, a2, 01, 01, 11, 00, 14, 45, 00, 17, 00, 1d, 45, 01, 12, 00, 1d, 31, 00, 36, 00, 37, 9e, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 17, b6, 01, 01, 11, 00, 14, 49, 00, 17, 00, 1d, 49, 01, 12, 00, 1d, 39, 01, 11, 00, 12, b2, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 17, be, 01, 03, 05, 00, 0b, c2, 01, 01, 01, 00, 02] +Raw bytes (325): 0x[01, 01, 12, 07, 05, 01, 09, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 01, 05, 09, 39, 01, 3d, 01, 00, 1d, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 1a, 01, 01, 09, 01, 12, 01, 01, 15, 00, 17, 05, 05, 09, 00, 0e, 09, 02, 09, 01, 11, 09, 04, 0d, 00, 1a, 02, 02, 0d, 00, 13, 02, 00, 14, 00, 1f, 00, 00, 2f, 00, 30, 02, 00, 31, 00, 35, 02, 00, 45, 00, 4f, 02, 00, 50, 00, 62, 02, 01, 0d, 00, 13, 02, 02, 11, 00, 1c, 00, 01, 11, 00, 12, 02, 02, 11, 00, 15, 02, 02, 11, 00, 1b, 02, 01, 15, 00, 27, 00, 02, 11, 00, 14, 02, 00, 17, 00, 1d, 02, 00, 1e, 00, 29, 02, 00, 41, 00, 42, 00, 00, 43, 00, 47, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 17, 00, 01, 11, 00, 14, 00, 00, 17, 00, 1d, 00, 00, 1e, 00, 29, 00, 00, 41, 00, 42, 00, 00, 43, 00, 47, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 17, 42, 04, 11, 00, 14, 42, 00, 17, 00, 1d, 42, 00, 1e, 00, 29, 00, 00, 42, 00, 43, 42, 00, 44, 00, 48, 00, 00, 61, 00, 62, 42, 01, 0d, 00, 17, 42, 01, 11, 00, 14, 42, 00, 17, 00, 1d, 42, 01, 12, 00, 1d, 00, 00, 36, 00, 37, 42, 01, 12, 00, 16, 00, 00, 2f, 00, 30, 42, 01, 0d, 00, 17, 42, 01, 11, 00, 14, 42, 00, 17, 00, 1d, 42, 01, 12, 00, 1d, 00, 01, 11, 00, 12, 42, 01, 12, 00, 16, 00, 01, 11, 00, 12, 42, 02, 0d, 00, 17, 46, 03, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => $DIR/try_error_result.rs -Number of expressions: 61 -- expression 0 operands: lhs = Counter(3), rhs = Counter(4) -- expression 1 operands: lhs = Counter(3), rhs = Expression(21, Add) -- expression 2 operands: lhs = Counter(4), rhs = Counter(5) -- expression 3 operands: lhs = Counter(3), rhs = Expression(21, Add) -- expression 4 operands: lhs = Counter(4), rhs = Counter(5) -- expression 5 operands: lhs = Counter(3), rhs = Expression(21, Add) -- expression 6 operands: lhs = Counter(4), rhs = Counter(5) -- expression 7 operands: lhs = Counter(3), rhs = Expression(19, Add) -- expression 8 operands: lhs = Expression(20, Add), rhs = Counter(7) -- expression 9 operands: lhs = Expression(21, Add), rhs = Counter(6) -- expression 10 operands: lhs = Counter(4), rhs = Counter(5) -- expression 11 operands: lhs = Counter(3), rhs = Expression(21, Add) -- expression 12 operands: lhs = Counter(4), rhs = Counter(5) -- expression 13 operands: lhs = Counter(3), rhs = Expression(21, Add) -- expression 14 operands: lhs = Counter(4), rhs = Counter(5) -- expression 15 operands: lhs = Counter(3), rhs = Expression(20, Add) -- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(6) -- expression 17 operands: lhs = Counter(4), rhs = Counter(5) -- expression 18 operands: lhs = Counter(3), rhs = Expression(19, Add) -- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(7) -- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(6) -- expression 21 operands: lhs = Counter(4), rhs = Counter(5) -- expression 22 operands: lhs = Counter(16), rhs = Expression(26, Add) -- expression 23 operands: lhs = Counter(8), rhs = Counter(9) -- expression 24 operands: lhs = Counter(16), rhs = Counter(8) -- expression 25 operands: lhs = Counter(16), rhs = Expression(26, Add) -- expression 26 operands: lhs = Counter(8), rhs = Counter(9) -- expression 27 operands: lhs = Counter(2), rhs = Expression(35, Add) -- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(11) -- expression 29 operands: lhs = Counter(3), rhs = Counter(10) -- expression 30 operands: lhs = Counter(2), rhs = Counter(3) -- expression 31 operands: lhs = Counter(2), rhs = Counter(3) -- expression 32 operands: lhs = Counter(2), rhs = Expression(36, Add) -- expression 33 operands: lhs = Counter(3), rhs = Counter(10) -- expression 34 operands: lhs = Counter(2), rhs = Expression(35, Add) -- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(11) -- expression 36 operands: lhs = Counter(3), rhs = Counter(10) -- expression 37 operands: lhs = Counter(17), rhs = Expression(41, Add) -- expression 38 operands: lhs = Counter(12), rhs = Counter(13) -- expression 39 operands: lhs = Counter(17), rhs = Counter(12) -- expression 40 operands: lhs = Counter(17), rhs = Expression(41, Add) -- expression 41 operands: lhs = Counter(12), rhs = Counter(13) -- expression 42 operands: lhs = Counter(18), rhs = Expression(46, Add) -- expression 43 operands: lhs = Counter(14), rhs = Counter(15) -- expression 44 operands: lhs = Counter(18), rhs = Counter(14) -- expression 45 operands: lhs = Counter(18), rhs = Expression(46, Add) -- expression 46 operands: lhs = Counter(14), rhs = Counter(15) -- expression 47 operands: lhs = Counter(1), rhs = Counter(2) -- expression 48 operands: lhs = Expression(49, Add), rhs = Counter(2) -- expression 49 operands: lhs = Expression(50, Add), rhs = Counter(15) -- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(14) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(13) -- expression 52 operands: lhs = Expression(53, Add), rhs = Counter(12) -- expression 53 operands: lhs = Expression(54, Add), rhs = Counter(11) -- expression 54 operands: lhs = Expression(55, Add), rhs = Counter(10) -- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(9) -- expression 56 operands: lhs = Expression(57, Add), rhs = Counter(8) -- expression 57 operands: lhs = Expression(58, Add), rhs = Counter(7) -- expression 58 operands: lhs = Expression(59, Add), rhs = Counter(6) -- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(5) -- expression 60 operands: lhs = Counter(1), rhs = Counter(4) +Number of expressions: 18 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(1), rhs = Counter(0) +- expression 3 operands: lhs = Counter(1), rhs = Counter(0) +- expression 4 operands: lhs = Counter(1), rhs = Counter(0) +- expression 5 operands: lhs = Counter(1), rhs = Counter(0) +- expression 6 operands: lhs = Counter(1), rhs = Counter(0) +- expression 7 operands: lhs = Counter(1), rhs = Counter(0) +- expression 8 operands: lhs = Counter(1), rhs = Counter(0) +- expression 9 operands: lhs = Counter(1), rhs = Counter(0) +- expression 10 operands: lhs = Counter(1), rhs = Counter(0) +- expression 11 operands: lhs = Counter(1), rhs = Counter(0) +- expression 12 operands: lhs = Counter(1), rhs = Counter(0) +- expression 13 operands: lhs = Counter(1), rhs = Counter(0) +- expression 14 operands: lhs = Counter(1), rhs = Counter(0) +- expression 15 operands: lhs = Counter(1), rhs = Counter(0) +- expression 16 operands: lhs = Counter(1), rhs = Counter(0) +- expression 17 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 57 - Code(Counter(0)) at (prev + 61, 1) to (start + 0, 29) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) @@ -166,83 +123,83 @@ Number of file 0 mappings: 57 - Code(Counter(1)) at (prev + 5, 9) to (start + 0, 14) - Code(Counter(2)) at (prev + 2, 9) to (start + 1, 17) - Code(Counter(2)) at (prev + 4, 13) to (start + 0, 26) -- Code(Counter(3)) at (prev + 2, 13) to (start + 0, 19) -- Code(Counter(3)) at (prev + 0, 20) to (start + 0, 31) -- Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) + = ((c0 + c2) - c1) +- Code(Expression(0, Sub)) at (prev + 0, 20) to (start + 0, 31) + = ((c0 + c2) - c1) +- Code(Zero) at (prev + 0, 47) to (start + 0, 48) - Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 0, 53) - = (c3 - c4) + = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 0, 69) to (start + 0, 79) - = (c3 - c4) + = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 0, 80) to (start + 0, 98) - = (c3 - c4) + = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 19) - = (c3 - c4) + = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 28) - = (c3 - c4) -- Code(Counter(5)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(13, Sub)) at (prev + 2, 17) to (start + 0, 21) - = (c3 - (c4 + c5)) -- Code(Expression(13, Sub)) at (prev + 2, 17) to (start + 0, 27) - = (c3 - (c4 + c5)) -- Code(Expression(13, Sub)) at (prev + 1, 21) to (start + 0, 39) - = (c3 - (c4 + c5)) -- Code(Expression(18, Sub)) at (prev + 2, 17) to (start + 0, 20) - = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(13, Sub)) at (prev + 0, 23) to (start + 0, 29) - = (c3 - (c4 + c5)) -- Code(Expression(13, Sub)) at (prev + 0, 30) to (start + 0, 41) - = (c3 - (c4 + c5)) -- Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(15, Sub)) at (prev + 0, 67) to (start + 0, 71) - = (c3 - ((c4 + c5) + c6)) -- Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) -- Code(Expression(18, Sub)) at (prev + 1, 13) to (start + 0, 23) - = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(25, Sub)) at (prev + 1, 17) to (start + 0, 20) - = (c16 - (c8 + c9)) -- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 29) -- Code(Counter(16)) at (prev + 0, 30) to (start + 0, 41) -- Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(24, Sub)) at (prev + 0, 67) to (start + 0, 71) - = (c16 - c8) -- Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) -- Code(Expression(25, Sub)) at (prev + 1, 13) to (start + 0, 23) - = (c16 - (c8 + c9)) -- Code(Expression(34, Sub)) at (prev + 4, 17) to (start + 0, 20) - = (c2 - ((c3 + c10) + c11)) -- Code(Expression(31, Sub)) at (prev + 0, 23) to (start + 0, 29) - = (c2 - c3) -- Code(Expression(31, Sub)) at (prev + 0, 30) to (start + 0, 41) - = (c2 - c3) -- Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) -- Code(Expression(32, Sub)) at (prev + 0, 68) to (start + 0, 72) - = (c2 - (c3 + c10)) -- Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) -- Code(Expression(34, Sub)) at (prev + 1, 13) to (start + 0, 23) - = (c2 - ((c3 + c10) + c11)) -- Code(Expression(40, Sub)) at (prev + 1, 17) to (start + 0, 20) - = (c17 - (c12 + c13)) -- Code(Counter(17)) at (prev + 0, 23) to (start + 0, 29) -- Code(Counter(17)) at (prev + 1, 18) to (start + 0, 29) -- Code(Counter(12)) at (prev + 0, 54) to (start + 0, 55) -- Code(Expression(39, Sub)) at (prev + 1, 18) to (start + 0, 22) - = (c17 - c12) -- Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 23) - = (c17 - (c12 + c13)) -- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20) - = (c18 - (c14 + c15)) -- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 29) -- Code(Counter(18)) at (prev + 1, 18) to (start + 0, 29) -- Code(Counter(14)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 22) - = (c18 - c14) -- Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 23) - = (c18 - (c14 + c15)) -- Code(Expression(47, Sub)) at (prev + 3, 5) to (start + 0, 11) + = ((c0 + c2) - c1) +- Code(Zero) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 21) + = ((c0 + c2) - c1) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 27) + = ((c0 + c2) - c1) +- Code(Expression(0, Sub)) at (prev + 1, 21) to (start + 0, 39) + = ((c0 + c2) - c1) +- Code(Zero) at (prev + 2, 17) to (start + 0, 20) +- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 29) + = ((c0 + c2) - c1) +- Code(Expression(0, Sub)) at (prev + 0, 30) to (start + 0, 41) + = ((c0 + c2) - c1) +- Code(Expression(0, Sub)) at (prev + 0, 65) to (start + 0, 66) + = ((c0 + c2) - c1) +- Code(Zero) at (prev + 0, 67) to (start + 0, 71) +- Code(Zero) at (prev + 0, 95) to (start + 0, 96) +- Code(Zero) at (prev + 1, 13) to (start + 0, 23) +- Code(Zero) at (prev + 1, 17) to (start + 0, 20) +- Code(Zero) at (prev + 0, 23) to (start + 0, 29) +- Code(Zero) at (prev + 0, 30) to (start + 0, 41) +- Code(Zero) at (prev + 0, 65) to (start + 0, 66) +- Code(Zero) at (prev + 0, 67) to (start + 0, 71) +- Code(Zero) at (prev + 0, 96) to (start + 0, 97) +- Code(Zero) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(16, Sub)) at (prev + 4, 17) to (start + 0, 20) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 0, 30) to (start + 0, 41) + = (c1 - c0) +- Code(Zero) at (prev + 0, 66) to (start + 0, 67) +- Code(Expression(16, Sub)) at (prev + 0, 68) to (start + 0, 72) + = (c1 - c0) +- Code(Zero) at (prev + 0, 97) to (start + 0, 98) +- Code(Expression(16, Sub)) at (prev + 1, 13) to (start + 0, 23) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 1, 17) to (start + 0, 20) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 1, 18) to (start + 0, 29) + = (c1 - c0) +- Code(Zero) at (prev + 0, 54) to (start + 0, 55) +- Code(Expression(16, Sub)) at (prev + 1, 18) to (start + 0, 22) + = (c1 - c0) +- Code(Zero) at (prev + 0, 47) to (start + 0, 48) +- Code(Expression(16, Sub)) at (prev + 1, 13) to (start + 0, 23) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 1, 17) to (start + 0, 20) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c1 - c0) +- Code(Expression(16, Sub)) at (prev + 1, 18) to (start + 0, 29) + = (c1 - c0) +- Code(Zero) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(16, Sub)) at (prev + 1, 18) to (start + 0, 22) + = (c1 - c0) +- Code(Zero) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(16, Sub)) at (prev + 2, 13) to (start + 0, 23) + = (c1 - c0) +- Code(Expression(17, Sub)) at (prev + 3, 5) to (start + 0, 11) = (c1 - c2) -- Code(Expression(48, Sub)) at (prev + 1, 1) to (start + 0, 2) - = (((((((((((((c1 + c4) + c5) + c6) + c7) + c8) + c9) + c10) + c11) + c12) + c13) + c14) + c15) - c2) -Highest counter ID seen: c18 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c2