22
33use std:: fmt:: { self , Debug , Formatter } ;
44
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 } ;
77use rustc_macros:: { HashStable , TyDecodable , TyEncodable } ;
88use rustc_span:: Span ;
99
@@ -103,23 +103,12 @@ pub enum CoverageKind {
103103 /// Should be erased before codegen (at some point after `InstrumentCoverage`).
104104 BlockMarker { id : BlockMarkerId } ,
105105
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.
107108 ///
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 } ,
123112
124113 /// Marks the point in MIR control flow represented by a evaluated condition.
125114 ///
@@ -138,8 +127,7 @@ impl Debug for CoverageKind {
138127 match self {
139128 SpanMarker => write ! ( fmt, "SpanMarker" ) ,
140129 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:?})" ) ,
143131 CondBitmapUpdate { index, decision_depth } => {
144132 write ! ( fmt, "CondBitmapUpdate(index={:?}, depth={:?})" , index, decision_depth)
145133 }
@@ -179,34 +167,19 @@ pub struct Expression {
179167#[ derive( TyEncodable , TyDecodable , Hash , HashStable ) ]
180168pub enum MappingKind {
181169 /// Associates a normal region of code with a counter/expression/zero.
182- Code ( CovTerm ) ,
170+ Code { bcb : BasicCoverageBlock } ,
183171 /// 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 } ,
185173 /// 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+ } ,
187179 /// Associates a decision region with a bitmap and number of conditions.
188180 MCDCDecision ( DecisionInfo ) ,
189181}
190182
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-
210183#[ derive( Clone , Debug ) ]
211184#[ derive( TyEncodable , TyDecodable , Hash , HashStable ) ]
212185pub struct Mapping {
@@ -222,10 +195,15 @@ pub struct Mapping {
222195pub struct FunctionCoverageInfo {
223196 pub function_source_hash : u64 ,
224197 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+
228204 pub mappings : Vec < Mapping > ,
205+
206+ pub mcdc_bitmap_bits : usize ,
229207 /// The depth of the deepest decision is used to know how many
230208 /// temp condbitmaps should be allocated for the function.
231209 pub mcdc_num_condition_bitmaps : usize ,
@@ -292,40 +270,55 @@ pub struct MCDCDecisionSpan {
292270 pub num_conditions : usize ,
293271}
294272
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.
298275///
299- /// Used by the `coverage_ids_info` query.
276+ /// Returned by the `coverage_ids_info` query.
300277#[ derive( Clone , TyEncodable , TyDecodable , Debug , HashStable ) ]
301278pub 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 > ,
304283}
305284
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 .
310289 ///
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 ;
319298 }
299+ }
320300
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 > ,
331324}
0 commit comments