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