@@ -2,19 +2,11 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
2
2
3
3
use rustc_data_structures:: fx:: FxIndexSet ;
4
4
use rustc_index:: bit_set:: BitSet ;
5
- use rustc_index:: IndexVec ;
6
5
use rustc_middle:: mir:: coverage:: {
7
- CodeRegion , CounterId , CovTerm , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
6
+ CodeRegion , CounterId , CovTerm , Expression , ExpressionId , FunctionCoverageInfo , Mapping , Op ,
8
7
} ;
9
8
use rustc_middle:: ty:: Instance ;
10
9
11
- #[ derive( Clone , Debug , PartialEq ) ]
12
- pub struct Expression {
13
- lhs : CovTerm ,
14
- op : Op ,
15
- rhs : CovTerm ,
16
- }
17
-
18
10
/// Holds all of the coverage mapping data associated with a function instance,
19
11
/// collected during traversal of `Coverage` statements in the function's MIR.
20
12
#[ derive( Debug ) ]
@@ -26,7 +18,7 @@ pub struct FunctionCoverage<'tcx> {
26
18
/// Tracks which counters have been seen, so that we can identify mappings
27
19
/// to counters that were optimized out, and set them to zero.
28
20
counters_seen : BitSet < CounterId > ,
29
- expressions : IndexVec < ExpressionId , Option < Expression > > ,
21
+ expressions_not_seen : BitSet < ExpressionId > ,
30
22
/// Tracks which expressions are known to always have a value of zero.
31
23
/// Only updated during the finalize step.
32
24
zero_expressions : FxIndexSet < ExpressionId > ,
@@ -55,16 +47,24 @@ impl<'tcx> FunctionCoverage<'tcx> {
55
47
is_used : bool ,
56
48
) -> Self {
57
49
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 ( ) ;
59
51
debug ! (
60
52
"FunctionCoverage::create(instance={instance:?}) has \
61
53
num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
62
54
) ;
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
+
63
63
Self {
64
64
function_coverage_info,
65
65
is_used,
66
66
counters_seen : BitSet :: new_empty ( num_counters) ,
67
- expressions : IndexVec :: from_elem_n ( None , num_expressions ) ,
67
+ expressions_not_seen ,
68
68
zero_expressions : FxIndexSet :: default ( ) ,
69
69
}
70
70
}
@@ -82,33 +82,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
82
82
83
83
/// Adds information about a coverage expression.
84
84
#[ 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 ( ) ;
92
87
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:?}" ,
99
91
) ;
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) ;
112
93
}
113
94
114
95
pub ( crate ) fn finalize ( & mut self ) {
@@ -133,13 +114,13 @@ impl<'tcx> FunctionCoverage<'tcx> {
133
114
// and then update the set of always-zero expressions if necessary.
134
115
// (By construction, expressions can only refer to other expressions
135
116
// 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,
139
120
// so any operand that refers to it can be replaced with zero.
140
121
zero_expressions. insert ( id) ;
141
122
continue ;
142
- } ;
123
+ }
143
124
144
125
// We don't need to simplify the actual expression data in the
145
126
// expressions list; we can just simplify a temporary copy and then
@@ -191,17 +172,17 @@ impl<'tcx> FunctionCoverage<'tcx> {
191
172
_ => Counter :: from_term ( operand) ,
192
173
} ;
193
174
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) {
198
180
// This expression ID was allocated, but we never saw the
199
181
// actual expression, so it must have been optimized out.
200
182
// Replace it with a dummy expression, and let LLVM take
201
183
// care of omitting it from the expression list.
202
184
CounterExpression :: DUMMY
203
- }
204
- & Some ( Expression { lhs, op, rhs, .. } ) => {
185
+ } else {
205
186
// Convert the operands and operator as normal.
206
187
CounterExpression :: new (
207
188
counter_from_operand ( lhs) ,
0 commit comments