@@ -2,19 +2,11 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
22
33use rustc_data_structures:: fx:: FxIndexSet ;
44use rustc_index:: bit_set:: BitSet ;
5- use rustc_index:: IndexVec ;
65use rustc_middle:: mir:: coverage:: {
7- CodeRegion , CounterId , CovTerm , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
6+ CodeRegion , CounterId , CovTerm , Expression , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
87} ;
98use rustc_middle:: ty:: Instance ;
109
11- #[ derive( Clone , Debug , PartialEq ) ]
12- pub struct Expression {
13- lhs : CovTerm ,
14- op : Op ,
15- rhs : CovTerm ,
16- }
17-
1810/// Holds all of the coverage mapping data associated with a function instance,
1911/// collected during traversal of `Coverage` statements in the function's MIR.
2012#[ derive( Debug ) ]
@@ -26,7 +18,7 @@ pub struct FunctionCoverage<'tcx> {
2618 /// Tracks which counters have been seen, so that we can identify mappings
2719 /// to counters that were optimized out, and set them to zero.
2820 counters_seen : BitSet < CounterId > ,
29- expressions : IndexVec < ExpressionId , Option < Expression > > ,
21+ expressions_not_seen : BitSet < ExpressionId > ,
3022 /// Tracks which expressions are known to always have a value of zero.
3123 /// Only updated during the finalize step.
3224 zero_expressions : FxIndexSet < ExpressionId > ,
@@ -55,16 +47,24 @@ impl<'tcx> FunctionCoverage<'tcx> {
5547 is_used : bool ,
5648 ) -> Self {
5749 let num_counters = function_coverage_info. num_counters ;
58- let num_expressions = function_coverage_info. num_expressions ;
50+ let num_expressions = function_coverage_info. expressions . len ( ) ;
5951 debug ! (
6052 "FunctionCoverage::create(instance={instance:?}) has \
6153 num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
6254 ) ;
55+
56+ let mut expressions_not_seen = BitSet :: new_empty ( num_expressions) ;
57+ for Mapping { term, .. } in & function_coverage_info. mappings {
58+ if let CovTerm :: Expression ( id) = term {
59+ expressions_not_seen. insert ( * id) ;
60+ }
61+ }
62+
6363 Self {
6464 function_coverage_info,
6565 is_used,
6666 counters_seen : BitSet :: new_empty ( num_counters) ,
67- expressions : IndexVec :: from_elem_n ( None , num_expressions ) ,
67+ expressions_not_seen ,
6868 zero_expressions : FxIndexSet :: default ( ) ,
6969 }
7070 }
@@ -82,33 +82,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
8282
8383 /// Adds information about a coverage expression.
8484 #[ instrument( level = "debug" , skip( self ) ) ]
85- pub ( crate ) fn add_counter_expression (
86- & mut self ,
87- expression_id : ExpressionId ,
88- lhs : CovTerm ,
89- op : Op ,
90- rhs : CovTerm ,
91- ) {
85+ pub ( crate ) fn add_counter_expression ( & mut self , expression_id : ExpressionId ) {
86+ let num_expressions = self . function_coverage_info . expressions . len ( ) ;
9287 debug_assert ! (
93- expression_id. as_usize( ) < self . expressions. len( ) ,
94- "expression_id {} is out of range for expressions.len() = {}
95- for {:?}" ,
96- expression_id. as_usize( ) ,
97- self . expressions. len( ) ,
98- self ,
88+ expression_id. as_usize( ) < num_expressions,
89+ "{expression_id:?} is out of range for expressions.len() = {num_expressions}
90+ for {self:?}" ,
9991 ) ;
100-
101- let expression = Expression { lhs, op, rhs } ;
102- let slot = & mut self . expressions [ expression_id] ;
103- match slot {
104- None => * slot = Some ( expression) ,
105- // If this expression ID slot has already been filled, it should
106- // contain identical information.
107- Some ( ref previous_expression) => assert_eq ! (
108- previous_expression, & expression,
109- "add_counter_expression: expression for id changed"
110- ) ,
111- }
92+ self . expressions_not_seen . remove ( expression_id) ;
11293 }
11394
11495 pub ( crate ) fn finalize ( & mut self ) {
@@ -133,13 +114,13 @@ impl<'tcx> FunctionCoverage<'tcx> {
133114 // and then update the set of always-zero expressions if necessary.
134115 // (By construction, expressions can only refer to other expressions
135116 // that have lower IDs, so one pass is sufficient.)
136- for ( id, maybe_expression ) in self . expressions . iter_enumerated ( ) {
137- let Some ( expression ) = maybe_expression else {
138- // If an expression is missing , it must have been optimized away,
117+ for ( id, expression ) in self . function_coverage_info . expressions . iter_enumerated ( ) {
118+ if self . expressions_not_seen . contains ( id ) {
119+ // If an expression was not seen , it must have been optimized away,
139120 // so any operand that refers to it can be replaced with zero.
140121 zero_expressions. insert ( id) ;
141122 continue ;
142- } ;
123+ }
143124
144125 // We don't need to simplify the actual expression data in the
145126 // expressions list; we can just simplify a temporary copy and then
@@ -191,17 +172,17 @@ impl<'tcx> FunctionCoverage<'tcx> {
191172 _ => Counter :: from_term ( operand) ,
192173 } ;
193174
194- self . expressions
195- . iter ( )
196- . map ( |expression| match expression {
197- None => {
175+ self . function_coverage_info
176+ . expressions
177+ . iter_enumerated ( )
178+ . map ( |( id, & Expression { lhs, op, rhs } ) | {
179+ if self . expressions_not_seen . contains ( id) {
198180 // This expression ID was allocated, but we never saw the
199181 // actual expression, so it must have been optimized out.
200182 // Replace it with a dummy expression, and let LLVM take
201183 // care of omitting it from the expression list.
202184 CounterExpression :: DUMMY
203- }
204- & Some ( Expression { lhs, op, rhs, .. } ) => {
185+ } else {
205186 // Convert the operands and operator as normal.
206187 CounterExpression :: new (
207188 counter_from_operand ( lhs) ,
0 commit comments