2
2
3
3
use std:: fmt:: { self , Debug , Formatter } ;
4
4
5
- use rustc_index :: IndexVec ;
6
- use rustc_index:: bit_set :: DenseBitSet ;
5
+ use rustc_data_structures :: fx :: FxIndexMap ;
6
+ use rustc_index:: { Idx , IndexVec } ;
7
7
use rustc_macros:: { HashStable , TyDecodable , TyEncodable } ;
8
8
use rustc_span:: Span ;
9
9
@@ -103,23 +103,12 @@ pub enum CoverageKind {
103
103
/// Should be erased before codegen (at some point after `InstrumentCoverage`).
104
104
BlockMarker { id : BlockMarkerId } ,
105
105
106
- /// Marks the point in MIR control flow represented by a coverage counter.
106
+ /// Marks its enclosing basic block with the ID of the coverage graph node
107
+ /// that it was part of during the `InstrumentCoverage` MIR pass.
107
108
///
108
- /// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR.
109
- ///
110
- /// If this statement does not survive MIR optimizations, any mappings that
111
- /// refer to this counter can have those references simplified to zero.
112
- CounterIncrement { id : CounterId } ,
113
-
114
- /// Marks the point in MIR control-flow represented by a coverage expression.
115
- ///
116
- /// If this statement does not survive MIR optimizations, any mappings that
117
- /// refer to this expression can have those references simplified to zero.
118
- ///
119
- /// (This is only inserted for expression IDs that are directly used by
120
- /// mappings. Intermediate expressions with no direct mappings are
121
- /// retained/zeroed based on whether they are transitively used.)
122
- ExpressionUsed { id : ExpressionId } ,
109
+ /// During codegen, this might be lowered to `llvm.instrprof.increment` or
110
+ /// to a no-op, depending on the outcome of counter-creation.
111
+ VirtualCounter { bcb : BasicCoverageBlock } ,
123
112
124
113
/// Marks the point in MIR control flow represented by a evaluated condition.
125
114
///
@@ -138,8 +127,7 @@ impl Debug for CoverageKind {
138
127
match self {
139
128
SpanMarker => write ! ( fmt, "SpanMarker" ) ,
140
129
BlockMarker { id } => write ! ( fmt, "BlockMarker({:?})" , id. index( ) ) ,
141
- CounterIncrement { id } => write ! ( fmt, "CounterIncrement({:?})" , id. index( ) ) ,
142
- ExpressionUsed { id } => write ! ( fmt, "ExpressionUsed({:?})" , id. index( ) ) ,
130
+ VirtualCounter { bcb } => write ! ( fmt, "VirtualCounter({bcb:?})" ) ,
143
131
CondBitmapUpdate { index, decision_depth } => {
144
132
write ! ( fmt, "CondBitmapUpdate(index={:?}, depth={:?})" , index, decision_depth)
145
133
}
@@ -179,34 +167,19 @@ pub struct Expression {
179
167
#[ derive( TyEncodable , TyDecodable , Hash , HashStable ) ]
180
168
pub enum MappingKind {
181
169
/// Associates a normal region of code with a counter/expression/zero.
182
- Code ( CovTerm ) ,
170
+ Code { bcb : BasicCoverageBlock } ,
183
171
/// Associates a branch region with separate counters for true and false.
184
- Branch { true_term : CovTerm , false_term : CovTerm } ,
172
+ Branch { true_bcb : BasicCoverageBlock , false_bcb : BasicCoverageBlock } ,
185
173
/// Associates a branch region with separate counters for true and false.
186
- MCDCBranch { true_term : CovTerm , false_term : CovTerm , mcdc_params : ConditionInfo } ,
174
+ MCDCBranch {
175
+ true_bcb : BasicCoverageBlock ,
176
+ false_bcb : BasicCoverageBlock ,
177
+ mcdc_params : ConditionInfo ,
178
+ } ,
187
179
/// Associates a decision region with a bitmap and number of conditions.
188
180
MCDCDecision ( DecisionInfo ) ,
189
181
}
190
182
191
- impl MappingKind {
192
- /// Returns a copy of this mapping kind, in which all coverage terms have
193
- /// been replaced with ones returned by the given function.
194
- pub fn map_terms ( & self , map_fn : impl Fn ( CovTerm ) -> CovTerm ) -> Self {
195
- match * self {
196
- Self :: Code ( term) => Self :: Code ( map_fn ( term) ) ,
197
- Self :: Branch { true_term, false_term } => {
198
- Self :: Branch { true_term : map_fn ( true_term) , false_term : map_fn ( false_term) }
199
- }
200
- Self :: MCDCBranch { true_term, false_term, mcdc_params } => Self :: MCDCBranch {
201
- true_term : map_fn ( true_term) ,
202
- false_term : map_fn ( false_term) ,
203
- mcdc_params,
204
- } ,
205
- Self :: MCDCDecision ( param) => Self :: MCDCDecision ( param) ,
206
- }
207
- }
208
- }
209
-
210
183
#[ derive( Clone , Debug ) ]
211
184
#[ derive( TyEncodable , TyDecodable , Hash , HashStable ) ]
212
185
pub struct Mapping {
@@ -222,10 +195,15 @@ pub struct Mapping {
222
195
pub struct FunctionCoverageInfo {
223
196
pub function_source_hash : u64 ,
224
197
pub body_span : Span ,
225
- pub num_counters : usize ,
226
- pub mcdc_bitmap_bits : usize ,
227
- pub expressions : IndexVec < ExpressionId , Expression > ,
198
+
199
+ /// Used in conjunction with `priority_list` to create physical counters
200
+ /// and counter expressions, after MIR optimizations.
201
+ pub node_flow_data : NodeFlowData < BasicCoverageBlock > ,
202
+ pub priority_list : Vec < BasicCoverageBlock > ,
203
+
228
204
pub mappings : Vec < Mapping > ,
205
+
206
+ pub mcdc_bitmap_bits : usize ,
229
207
/// The depth of the deepest decision is used to know how many
230
208
/// temp condbitmaps should be allocated for the function.
231
209
pub mcdc_num_condition_bitmaps : usize ,
@@ -292,40 +270,55 @@ pub struct MCDCDecisionSpan {
292
270
pub num_conditions : usize ,
293
271
}
294
272
295
- /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
296
- /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
297
- /// have had a chance to potentially remove some of them.
273
+ /// Contains information needed during codegen, obtained by inspecting the
274
+ /// function's MIR after MIR optimizations.
298
275
///
299
- /// Used by the `coverage_ids_info` query.
276
+ /// Returned by the `coverage_ids_info` query.
300
277
#[ derive( Clone , TyEncodable , TyDecodable , Debug , HashStable ) ]
301
278
pub struct CoverageIdsInfo {
302
- pub counters_seen : DenseBitSet < CounterId > ,
303
- pub zero_expressions : DenseBitSet < ExpressionId > ,
279
+ pub num_counters : u32 ,
280
+ pub phys_counter_for_node : FxIndexMap < BasicCoverageBlock , CounterId > ,
281
+ pub term_for_bcb : IndexVec < BasicCoverageBlock , Option < CovTerm > > ,
282
+ pub expressions : IndexVec < ExpressionId , Expression > ,
304
283
}
305
284
306
- impl CoverageIdsInfo {
307
- /// Coverage codegen needs to know how many coverage counters are ever
308
- /// incremented within a function, so that it can set the `num-counters`
309
- /// argument of the `llvm.instrprof.increment` intrinsic .
285
+ rustc_index :: newtype_index! {
286
+ /// During the `InstrumentCoverage` MIR pass, a BCB is a node in the
287
+ /// "coverage graph", which is a refinement of the MIR control-flow graph
288
+ /// that merges or omits some blocks that aren't relevant to coverage .
310
289
///
311
- /// This may be less than the highest counter ID emitted by the
312
- /// InstrumentCoverage MIR pass, if the highest-numbered counter increments
313
- /// were removed by MIR optimizations.
314
- pub fn num_counters_after_mir_opts ( & self ) -> u32 {
315
- // FIXME(Zalathar): Currently this treats an unused counter as "used"
316
- // if its ID is less than that of the highest counter that really is
317
- // used. Fixing this would require adding a renumbering step somewhere.
318
- self . counters_seen . last_set_in ( .. ) . map_or ( 0 , |max| max . as_u32 ( ) + 1 )
290
+ /// After that pass is complete, the coverage graph no longer exists, so a
291
+ /// BCB is effectively an opaque ID.
292
+ # [ derive ( HashStable ) ]
293
+ # [ encodable ]
294
+ # [ orderable ]
295
+ # [ debug_format = "bcb{}" ]
296
+ pub struct BasicCoverageBlock {
297
+ const START_BCB = 0 ;
319
298
}
299
+ }
320
300
321
- /// Returns `true` if the given term is known to have a value of zero, taking
322
- /// into account knowledge of which counters are unused and which expressions
323
- /// are always zero.
324
- pub fn is_zero_term ( & self , term : CovTerm ) -> bool {
325
- match term {
326
- CovTerm :: Zero => true ,
327
- CovTerm :: Counter ( id) => !self . counters_seen . contains ( id) ,
328
- CovTerm :: Expression ( id) => self . zero_expressions . contains ( id) ,
329
- }
330
- }
301
+ /// Data representing a view of some underlying graph, in which each node's
302
+ /// successors have been merged into a single "supernode".
303
+ ///
304
+ /// The resulting supernodes have no obvious meaning on their own.
305
+ /// However, merging successor nodes means that a node's out-edges can all
306
+ /// be combined into a single out-edge, whose flow is the same as the flow
307
+ /// (execution count) of its corresponding node in the original graph.
308
+ ///
309
+ /// With all node flows now in the original graph now represented as edge flows
310
+ /// in the merged graph, it becomes possible to analyze the original node flows
311
+ /// using techniques for analyzing edge flows.
312
+ #[ derive( Clone , Debug ) ]
313
+ #[ derive( TyEncodable , TyDecodable , Hash , HashStable ) ]
314
+ pub struct NodeFlowData < Node : Idx > {
315
+ /// Maps each node to the supernode that contains it, indicated by some
316
+ /// arbitrary "root" node that is part of that supernode.
317
+ pub supernodes : IndexVec < Node , Node > ,
318
+ /// For each node, stores the single supernode that all of its successors
319
+ /// have been merged into.
320
+ ///
321
+ /// (Note that each node in a supernode can potentially have a _different_
322
+ /// successor supernode from its peers.)
323
+ pub succ_supernodes : IndexVec < Node , Node > ,
331
324
}
0 commit comments