1
1
use rustc_data_structures:: captures:: Captures ;
2
2
use rustc_data_structures:: fx:: FxIndexSet ;
3
3
use rustc_index:: bit_set:: BitSet ;
4
+ use rustc_middle:: mir:: CoverageIdsInfo ;
4
5
use rustc_middle:: mir:: coverage:: {
5
6
CounterId , CovTerm , Expression , ExpressionId , FunctionCoverageInfo , Mapping , MappingKind , Op ,
6
7
SourceRegion ,
7
8
} ;
8
9
use rustc_middle:: ty:: Instance ;
9
- use tracing:: { debug, instrument } ;
10
+ use tracing:: debug;
10
11
11
12
use crate :: coverageinfo:: ffi:: { Counter , CounterExpression , ExprKind } ;
12
13
@@ -16,39 +17,33 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
16
17
pub ( crate ) struct FunctionCoverageCollector < ' tcx > {
17
18
/// Coverage info that was attached to this function by the instrumentor.
18
19
function_coverage_info : & ' tcx FunctionCoverageInfo ,
20
+ ids_info : & ' tcx CoverageIdsInfo ,
19
21
is_used : bool ,
20
-
21
- /// Tracks which counters have been seen, so that we can identify mappings
22
- /// to counters that were optimized out, and set them to zero.
23
- counters_seen : BitSet < CounterId > ,
24
- /// Contains all expression IDs that have been seen in an `ExpressionUsed`
25
- /// coverage statement, plus all expression IDs that aren't directly used
26
- /// by any mappings (and therefore do not have expression-used statements).
27
- /// After MIR traversal is finished, we can conclude that any IDs missing
28
- /// from this set must have had their statements deleted by MIR opts.
29
- expressions_seen : BitSet < ExpressionId > ,
30
22
}
31
23
32
24
impl < ' tcx > FunctionCoverageCollector < ' tcx > {
33
25
/// Creates a new set of coverage data for a used (called) function.
34
26
pub ( crate ) fn new (
35
27
instance : Instance < ' tcx > ,
36
28
function_coverage_info : & ' tcx FunctionCoverageInfo ,
29
+ ids_info : & ' tcx CoverageIdsInfo ,
37
30
) -> Self {
38
- Self :: create ( instance, function_coverage_info, true )
31
+ Self :: create ( instance, function_coverage_info, ids_info , true )
39
32
}
40
33
41
34
/// Creates a new set of coverage data for an unused (never called) function.
42
35
pub ( crate ) fn unused (
43
36
instance : Instance < ' tcx > ,
44
37
function_coverage_info : & ' tcx FunctionCoverageInfo ,
38
+ ids_info : & ' tcx CoverageIdsInfo ,
45
39
) -> Self {
46
- Self :: create ( instance, function_coverage_info, false )
40
+ Self :: create ( instance, function_coverage_info, ids_info , false )
47
41
}
48
42
49
43
fn create (
50
44
instance : Instance < ' tcx > ,
51
45
function_coverage_info : & ' tcx FunctionCoverageInfo ,
46
+ ids_info : & ' tcx CoverageIdsInfo ,
52
47
is_used : bool ,
53
48
) -> Self {
54
49
let num_counters = function_coverage_info. num_counters ;
@@ -58,44 +53,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
58
53
num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
59
54
) ;
60
55
61
- // Create a filled set of expression IDs, so that expressions not
62
- // directly used by mappings will be treated as "seen".
63
- // (If they end up being unused, LLVM will delete them for us.)
64
- let mut expressions_seen = BitSet :: new_filled ( num_expressions) ;
65
- // For each expression ID that is directly used by one or more mappings,
66
- // mark it as not-yet-seen. This indicates that we expect to see a
67
- // corresponding `ExpressionUsed` statement during MIR traversal.
68
- for mapping in function_coverage_info. mappings . iter ( ) {
69
- // Currently we only worry about ordinary code mappings.
70
- // For branch and MC/DC mappings, expressions might not correspond
71
- // to any particular point in the control-flow graph.
72
- // (Keep this in sync with the injection of `ExpressionUsed`
73
- // statements in the `InstrumentCoverage` MIR pass.)
74
- if let MappingKind :: Code ( term) = mapping. kind
75
- && let CovTerm :: Expression ( id) = term
76
- {
77
- expressions_seen. remove ( id) ;
78
- }
79
- }
80
-
81
- Self {
82
- function_coverage_info,
83
- is_used,
84
- counters_seen : BitSet :: new_empty ( num_counters) ,
85
- expressions_seen,
86
- }
87
- }
88
-
89
- /// Marks a counter ID as having been seen in a counter-increment statement.
90
- #[ instrument( level = "debug" , skip( self ) ) ]
91
- pub ( crate ) fn mark_counter_id_seen ( & mut self , id : CounterId ) {
92
- self . counters_seen . insert ( id) ;
93
- }
94
-
95
- /// Marks an expression ID as having been seen in an expression-used statement.
96
- #[ instrument( level = "debug" , skip( self ) ) ]
97
- pub ( crate ) fn mark_expression_id_seen ( & mut self , id : ExpressionId ) {
98
- self . expressions_seen . insert ( id) ;
56
+ Self { function_coverage_info, ids_info, is_used }
99
57
}
100
58
101
59
/// Identify expressions that will always have a value of zero, and note
@@ -117,7 +75,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
117
75
// (By construction, expressions can only refer to other expressions
118
76
// that have lower IDs, so one pass is sufficient.)
119
77
for ( id, expression) in self . function_coverage_info . expressions . iter_enumerated ( ) {
120
- if !self . expressions_seen . contains ( id) {
78
+ if !self . is_used || ! self . ids_info . expressions_seen . contains ( id) {
121
79
// If an expression was not seen, it must have been optimized away,
122
80
// so any operand that refers to it can be replaced with zero.
123
81
zero_expressions. insert ( id) ;
@@ -146,7 +104,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
146
104
assert_operand_expression_is_lower ( id) ;
147
105
}
148
106
149
- if is_zero_term ( & self . counters_seen , & zero_expressions, * operand) {
107
+ if is_zero_term ( & self . ids_info . counters_seen , & zero_expressions, * operand) {
150
108
* operand = CovTerm :: Zero ;
151
109
}
152
110
} ;
@@ -172,17 +130,17 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
172
130
173
131
pub ( crate ) fn into_finished ( self ) -> FunctionCoverage < ' tcx > {
174
132
let zero_expressions = self . identify_zero_expressions ( ) ;
175
- let FunctionCoverageCollector { function_coverage_info, is_used , counters_seen , .. } = self ;
133
+ let FunctionCoverageCollector { function_coverage_info, ids_info , is_used , .. } = self ;
176
134
177
- FunctionCoverage { function_coverage_info, is_used , counters_seen , zero_expressions }
135
+ FunctionCoverage { function_coverage_info, ids_info , is_used , zero_expressions }
178
136
}
179
137
}
180
138
181
139
pub ( crate ) struct FunctionCoverage < ' tcx > {
182
140
pub ( crate ) function_coverage_info : & ' tcx FunctionCoverageInfo ,
141
+ ids_info : & ' tcx CoverageIdsInfo ,
183
142
is_used : bool ,
184
143
185
- counters_seen : BitSet < CounterId > ,
186
144
zero_expressions : ZeroExpressions ,
187
145
}
188
146
@@ -238,7 +196,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
238
196
}
239
197
240
198
fn is_zero_term ( & self , term : CovTerm ) -> bool {
241
- is_zero_term ( & self . counters_seen , & self . zero_expressions , term)
199
+ ! self . is_used || is_zero_term ( & self . ids_info . counters_seen , & self . zero_expressions , term)
242
200
}
243
201
}
244
202
0 commit comments