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