rustc_codegen_llvm/coverageinfo/
ffi.rs

1use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId};
2
3/// Must match the layout of `LLVMRustCounterKind`.
4#[derive(Copy, Clone, Debug)]
5#[repr(C)]
6pub(crate) enum CounterKind {
7    Zero = 0,
8    CounterValueReference = 1,
9    Expression = 2,
10}
11
12/// A reference to an instance of an abstract "counter" that will yield a value in a coverage
13/// report. Note that `id` has different interpretations, depending on the `kind`:
14///   * For `CounterKind::Zero`, `id` is assumed to be `0`
15///   * For `CounterKind::CounterValueReference`,  `id` matches the `counter_id` of the injected
16///     instrumentation counter (the `index` argument to the LLVM intrinsic
17///     `instrprof.increment()`)
18///   * For `CounterKind::Expression`, `id` is the index into the coverage map's array of
19///     counter expressions.
20///
21/// Corresponds to struct `llvm::coverage::Counter`.
22///
23/// Must match the layout of `LLVMRustCounter`.
24#[derive(Copy, Clone, Debug)]
25#[repr(C)]
26pub(crate) struct Counter {
27    // Important: The layout (order and types of fields) must match its C++ counterpart.
28    pub(crate) kind: CounterKind,
29    id: u32,
30}
31
32impl Counter {
33    /// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used.
34    pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 };
35
36    /// Constructs a new `Counter` of kind `CounterValueReference`.
37    pub(crate) fn counter_value_reference(counter_id: CounterId) -> Self {
38        Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() }
39    }
40
41    /// Constructs a new `Counter` of kind `Expression`.
42    pub(crate) fn expression(expression_id: ExpressionId) -> Self {
43        Self { kind: CounterKind::Expression, id: expression_id.as_u32() }
44    }
45
46    pub(crate) fn from_term(term: CovTerm) -> Self {
47        match term {
48            CovTerm::Zero => Self::ZERO,
49            CovTerm::Counter(id) => Self::counter_value_reference(id),
50            CovTerm::Expression(id) => Self::expression(id),
51        }
52    }
53}
54
55/// Corresponds to enum `llvm::coverage::CounterExpression::ExprKind`.
56///
57/// Must match the layout of `LLVMRustCounterExprKind`.
58#[derive(Copy, Clone, Debug)]
59#[repr(C)]
60pub(crate) enum ExprKind {
61    Subtract = 0,
62    Add = 1,
63}
64
65/// Corresponds to struct `llvm::coverage::CounterExpression`.
66///
67/// Must match the layout of `LLVMRustCounterExpression`.
68#[derive(Copy, Clone, Debug)]
69#[repr(C)]
70pub(crate) struct CounterExpression {
71    pub(crate) kind: ExprKind,
72    pub(crate) lhs: Counter,
73    pub(crate) rhs: Counter,
74}
75
76/// A span of source code coordinates to be embedded in coverage metadata.
77///
78/// Must match the layout of `LLVMRustCoverageSpan`.
79#[derive(Clone, Debug)]
80#[repr(C)]
81pub(crate) struct CoverageSpan {
82    /// Local index into the function's local-to-global file ID table.
83    /// The value at that index is itself an index into the coverage filename
84    /// table in the CGU's `__llvm_covmap` section.
85    pub(crate) file_id: u32,
86
87    /// 1-based starting line of the source code span.
88    pub(crate) start_line: u32,
89    /// 1-based starting column of the source code span.
90    pub(crate) start_col: u32,
91    /// 1-based ending line of the source code span.
92    pub(crate) end_line: u32,
93    /// 1-based ending column of the source code span. High bit must be unset.
94    pub(crate) end_col: u32,
95}
96
97/// Holds tables of the various region types in one struct.
98///
99/// Don't pass this struct across FFI; pass the individual region tables as
100/// pointer/length pairs instead.
101///
102/// Each field name has a `_regions` suffix for improved readability after
103/// exhaustive destructing, which ensures that all region types are handled.
104#[derive(Clone, Debug, Default)]
105pub(crate) struct Regions {
106    pub(crate) code_regions: Vec<CodeRegion>,
107    pub(crate) expansion_regions: Vec<ExpansionRegion>,
108    pub(crate) branch_regions: Vec<BranchRegion>,
109}
110
111impl Regions {
112    /// Returns true if none of this structure's tables contain any regions.
113    pub(crate) fn has_no_regions(&self) -> bool {
114        let Self { code_regions, expansion_regions, branch_regions } = self;
115
116        code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty()
117    }
118}
119
120/// Must match the layout of `LLVMRustCoverageCodeRegion`.
121#[derive(Clone, Debug)]
122#[repr(C)]
123pub(crate) struct CodeRegion {
124    pub(crate) cov_span: CoverageSpan,
125    pub(crate) counter: Counter,
126}
127
128/// Must match the layout of `LLVMRustCoverageExpansionRegion`.
129#[derive(Clone, Debug)]
130#[repr(C)]
131pub(crate) struct ExpansionRegion {
132    pub(crate) cov_span: CoverageSpan,
133    pub(crate) expanded_file_id: u32,
134}
135
136/// Must match the layout of `LLVMRustCoverageBranchRegion`.
137#[derive(Clone, Debug)]
138#[repr(C)]
139pub(crate) struct BranchRegion {
140    pub(crate) cov_span: CoverageSpan,
141    pub(crate) true_counter: Counter,
142    pub(crate) false_counter: Counter,
143}