11use rustc_data_structures:: captures:: Captures ;
2- use rustc_index:: IndexSlice ;
32use rustc_index:: bit_set:: DenseBitSet ;
43use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
5- use rustc_middle:: mir:: coverage:: {
6- BasicCoverageBlock , CounterId , CovTerm , CoverageIdsInfo , CoverageKind , Expression ,
7- ExpressionId , MappingKind , Op ,
8- } ;
4+ use rustc_middle:: mir:: coverage:: { BasicCoverageBlock , CoverageIdsInfo , CoverageKind , MappingKind } ;
95use rustc_middle:: mir:: { Body , Statement , StatementKind } ;
106use rustc_middle:: query:: TyCtxtAt ;
117use rustc_middle:: ty:: { self , TyCtxt } ;
@@ -136,44 +132,12 @@ fn coverage_ids_info<'tcx>(
136132 let node_counters = make_node_counters ( & fn_cov_info. node_flow_data , & fn_cov_info. priority_list ) ;
137133 let coverage_counters = transcribe_counters ( & node_counters, & bcb_needs_counter, & bcbs_seen) ;
138134
139- let mut counters_seen = DenseBitSet :: new_empty ( coverage_counters. node_counters . len ( ) ) ;
140- let mut expressions_seen = DenseBitSet :: new_filled ( coverage_counters. expressions . len ( ) ) ;
141-
142- // For each expression ID that is directly used by one or more mappings,
143- // mark it as not-yet-seen. This indicates that we expect to see a
144- // corresponding `VirtualCounter` statement during MIR traversal.
145- for mapping in fn_cov_info. mappings . iter ( ) {
146- // Currently we only worry about ordinary code mappings.
147- // For branch and MC/DC mappings, expressions might not correspond
148- // to any particular point in the control-flow graph.
149- if let MappingKind :: Code { bcb } = mapping. kind
150- && let Some ( CovTerm :: Expression ( id) ) = coverage_counters. node_counters [ bcb]
151- {
152- expressions_seen. remove ( id) ;
153- }
154- }
155-
156- for bcb in bcbs_seen. iter ( ) {
157- if let Some ( & id) = coverage_counters. phys_counter_for_node . get ( & bcb) {
158- counters_seen. insert ( id) ;
159- }
160- if let Some ( CovTerm :: Expression ( id) ) = coverage_counters. node_counters [ bcb] {
161- expressions_seen. insert ( id) ;
162- }
163- }
164-
165- let zero_expressions = identify_zero_expressions (
166- & coverage_counters. expressions ,
167- & counters_seen,
168- & expressions_seen,
169- ) ;
170-
171- let CoverageCounters { phys_counter_for_node, node_counters, expressions, .. } =
172- coverage_counters;
135+ let CoverageCounters {
136+ phys_counter_for_node, next_counter_id, node_counters, expressions, ..
137+ } = coverage_counters;
173138
174139 Some ( CoverageIdsInfo {
175- counters_seen,
176- zero_expressions,
140+ num_counters : next_counter_id. as_u32 ( ) ,
177141 phys_counter_for_node,
178142 term_for_bcb : node_counters,
179143 expressions,
@@ -195,94 +159,3 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
195159 let scope_data = & body. source_scopes [ statement. source_info . scope ] ;
196160 scope_data. inlined . is_some ( ) || scope_data. inlined_parent_scope . is_some ( )
197161}
198-
199- /// Identify expressions that will always have a value of zero, and note their
200- /// IDs in a `DenseBitSet`. Mappings that refer to a zero expression can instead
201- /// become mappings to a constant zero value.
202- ///
203- /// This function mainly exists to preserve the simplifications that were
204- /// already being performed by the Rust-side expression renumbering, so that
205- /// the resulting coverage mappings don't get worse.
206- fn identify_zero_expressions (
207- expressions : & IndexSlice < ExpressionId , Expression > ,
208- counters_seen : & DenseBitSet < CounterId > ,
209- expressions_seen : & DenseBitSet < ExpressionId > ,
210- ) -> DenseBitSet < ExpressionId > {
211- // The set of expressions that either were optimized out entirely, or
212- // have zero as both of their operands, and will therefore always have
213- // a value of zero. Other expressions that refer to these as operands
214- // can have those operands replaced with `CovTerm::Zero`.
215- let mut zero_expressions = DenseBitSet :: new_empty ( expressions. len ( ) ) ;
216-
217- // Simplify a copy of each expression based on lower-numbered expressions,
218- // and then update the set of always-zero expressions if necessary.
219- // (By construction, expressions can only refer to other expressions
220- // that have lower IDs, so one pass is sufficient.)
221- for ( id, expression) in expressions. iter_enumerated ( ) {
222- if !expressions_seen. contains ( id) {
223- // If an expression was not seen, it must have been optimized away,
224- // so any operand that refers to it can be replaced with zero.
225- zero_expressions. insert ( id) ;
226- continue ;
227- }
228-
229- // We don't need to simplify the actual expression data in the
230- // expressions list; we can just simplify a temporary copy and then
231- // use that to update the set of always-zero expressions.
232- let Expression { mut lhs, op, mut rhs } = * expression;
233-
234- // If an expression has an operand that is also an expression, the
235- // operand's ID must be strictly lower. This is what lets us find
236- // all zero expressions in one pass.
237- let assert_operand_expression_is_lower = |operand_id : ExpressionId | {
238- assert ! (
239- operand_id < id,
240- "Operand {operand_id:?} should be less than {id:?} in {expression:?}" ,
241- )
242- } ;
243-
244- // If an operand refers to a counter or expression that is always
245- // zero, then that operand can be replaced with `CovTerm::Zero`.
246- let maybe_set_operand_to_zero = |operand : & mut CovTerm | {
247- if let CovTerm :: Expression ( id) = * operand {
248- assert_operand_expression_is_lower ( id) ;
249- }
250-
251- if is_zero_term ( & counters_seen, & zero_expressions, * operand) {
252- * operand = CovTerm :: Zero ;
253- }
254- } ;
255- maybe_set_operand_to_zero ( & mut lhs) ;
256- maybe_set_operand_to_zero ( & mut rhs) ;
257-
258- // Coverage counter values cannot be negative, so if an expression
259- // involves subtraction from zero, assume that its RHS must also be zero.
260- // (Do this after simplifications that could set the LHS to zero.)
261- if lhs == CovTerm :: Zero && op == Op :: Subtract {
262- rhs = CovTerm :: Zero ;
263- }
264-
265- // After the above simplifications, if both operands are zero, then
266- // we know that this expression is always zero too.
267- if lhs == CovTerm :: Zero && rhs == CovTerm :: Zero {
268- zero_expressions. insert ( id) ;
269- }
270- }
271-
272- zero_expressions
273- }
274-
275- /// Returns `true` if the given term is known to have a value of zero, taking
276- /// into account knowledge of which counters are unused and which expressions
277- /// are always zero.
278- fn is_zero_term (
279- counters_seen : & DenseBitSet < CounterId > ,
280- zero_expressions : & DenseBitSet < ExpressionId > ,
281- term : CovTerm ,
282- ) -> bool {
283- match term {
284- CovTerm :: Zero => true ,
285- CovTerm :: Counter ( id) => !counters_seen. contains ( id) ,
286- CovTerm :: Expression ( id) => zero_expressions. contains ( id) ,
287- }
288- }
0 commit comments