@@ -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,12 @@ 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+ /// Contains all expression IDs that have been seen in an `ExpressionUsed`
22+ /// coverage statement, plus all expression IDs that aren't directly used
23+ /// by any mappings (and therefore do not have expression-used statements).
24+ /// After MIR traversal is finished, we can conclude that any IDs missing
25+ /// from this set must have had their statements deleted by MIR opts.
26+ expressions_seen : BitSet < ExpressionId > ,
3027}
3128
3229impl < ' tcx > FunctionCoverage < ' tcx > {
@@ -52,16 +49,30 @@ impl<'tcx> FunctionCoverage<'tcx> {
5249 is_used : bool ,
5350 ) -> Self {
5451 let num_counters = function_coverage_info. num_counters ;
55- let num_expressions = function_coverage_info. num_expressions ;
52+ let num_expressions = function_coverage_info. expressions . len ( ) ;
5653 debug ! (
5754 "FunctionCoverage::create(instance={instance:?}) has \
5855 num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
5956 ) ;
57+
58+ // Create a filled set of expression IDs, so that expressions not
59+ // directly used by mappings will be treated as "seen".
60+ // (If they end up being unused, LLVM will delete them for us.)
61+ let mut expressions_seen = BitSet :: new_filled ( num_expressions) ;
62+ // For each expression ID that is directly used by one or more mappings,
63+ // mark it as not-yet-seen. This indicates that we expect to see a
64+ // corresponding `ExpressionUsed` statement during MIR traversal.
65+ for Mapping { term, .. } in & function_coverage_info. mappings {
66+ if let & CovTerm :: Expression ( id) = term {
67+ expressions_seen. remove ( id) ;
68+ }
69+ }
70+
6071 Self {
6172 function_coverage_info,
6273 is_used,
6374 counters_seen : BitSet :: new_empty ( num_counters) ,
64- expressions : IndexVec :: from_elem_n ( None , num_expressions ) ,
75+ expressions_seen ,
6576 }
6677 }
6778
@@ -76,35 +87,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
7687 self . counters_seen . insert ( id) ;
7788 }
7889
79- /// Adds information about a coverage expression.
90+ /// Marks an expression ID as having been seen in an expression-used statement .
8091 #[ instrument( level = "debug" , skip( self ) ) ]
81- pub ( crate ) fn add_counter_expression (
82- & mut self ,
83- expression_id : ExpressionId ,
84- lhs : CovTerm ,
85- op : Op ,
86- rhs : CovTerm ,
87- ) {
88- debug_assert ! (
89- expression_id. as_usize( ) < self . expressions. len( ) ,
90- "expression_id {} is out of range for expressions.len() = {}
91- for {:?}" ,
92- expression_id. as_usize( ) ,
93- self . expressions. len( ) ,
94- self ,
95- ) ;
96-
97- let expression = Expression { lhs, op, rhs } ;
98- let slot = & mut self . expressions [ expression_id] ;
99- match slot {
100- None => * slot = Some ( expression) ,
101- // If this expression ID slot has already been filled, it should
102- // contain identical information.
103- Some ( ref previous_expression) => assert_eq ! (
104- previous_expression, & expression,
105- "add_counter_expression: expression for id changed"
106- ) ,
107- }
92+ pub ( crate ) fn mark_expression_id_seen ( & mut self , id : ExpressionId ) {
93+ self . expressions_seen . insert ( id) ;
10894 }
10995
11096 /// Identify expressions that will always have a value of zero, and note
@@ -125,13 +111,13 @@ impl<'tcx> FunctionCoverage<'tcx> {
125111 // and then update the set of always-zero expressions if necessary.
126112 // (By construction, expressions can only refer to other expressions
127113 // that have lower IDs, so one pass is sufficient.)
128- for ( id, maybe_expression ) in self . expressions . iter_enumerated ( ) {
129- let Some ( expression ) = maybe_expression else {
130- // If an expression is missing , it must have been optimized away,
114+ for ( id, expression ) in self . function_coverage_info . expressions . iter_enumerated ( ) {
115+ if ! self . expressions_seen . contains ( id ) {
116+ // If an expression was not seen , it must have been optimized away,
131117 // so any operand that refers to it can be replaced with zero.
132118 zero_expressions. insert ( id) ;
133119 continue ;
134- } ;
120+ }
135121
136122 // We don't need to simplify the actual expression data in the
137123 // expressions list; we can just simplify a temporary copy and then
@@ -197,7 +183,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
197183 // Expression IDs are indices into `self.expressions`, and on the LLVM
198184 // side they will be treated as indices into `counter_expressions`, so
199185 // the two vectors should correspond 1:1.
200- assert_eq ! ( self . expressions. len( ) , counter_expressions. len( ) ) ;
186+ assert_eq ! ( self . function_coverage_info . expressions. len( ) , counter_expressions. len( ) ) ;
201187
202188 let counter_regions = self . counter_regions ( zero_expressions) ;
203189
@@ -217,27 +203,16 @@ impl<'tcx> FunctionCoverage<'tcx> {
217203 _ => Counter :: from_term ( operand) ,
218204 } ;
219205
220- self . expressions
206+ self . function_coverage_info
207+ . expressions
221208 . iter ( )
222- . map ( |expression| match expression {
223- None => {
224- // This expression ID was allocated, but we never saw the
225- // actual expression, so it must have been optimized out.
226- // Replace it with a dummy expression, and let LLVM take
227- // care of omitting it from the expression list.
228- CounterExpression :: DUMMY
229- }
230- & Some ( Expression { lhs, op, rhs, .. } ) => {
231- // Convert the operands and operator as normal.
232- CounterExpression :: new (
233- counter_from_operand ( lhs) ,
234- match op {
235- Op :: Add => ExprKind :: Add ,
236- Op :: Subtract => ExprKind :: Subtract ,
237- } ,
238- counter_from_operand ( rhs) ,
239- )
240- }
209+ . map ( |& Expression { lhs, op, rhs } | CounterExpression {
210+ lhs : counter_from_operand ( lhs) ,
211+ kind : match op {
212+ Op :: Add => ExprKind :: Add ,
213+ Op :: Subtract => ExprKind :: Subtract ,
214+ } ,
215+ rhs : counter_from_operand ( rhs) ,
241216 } )
242217 . collect :: < Vec < _ > > ( )
243218 }
0 commit comments