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
76pub(crate) mod mcdc {
77    use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
78
79    /// Must match the layout of `LLVMRustMCDCDecisionParameters`.
80    #[repr(C)]
81    #[derive(Clone, Copy, Debug, Default)]
82    pub(crate) struct DecisionParameters {
83        bitmap_idx: u32,
84        num_conditions: u16,
85    }
86
87    type LLVMConditionId = i16;
88
89    /// Must match the layout of `LLVMRustMCDCBranchParameters`.
90    #[repr(C)]
91    #[derive(Clone, Copy, Debug, Default)]
92    pub(crate) struct BranchParameters {
93        condition_id: LLVMConditionId,
94        condition_ids: [LLVMConditionId; 2],
95    }
96
97    impl From<ConditionInfo> for BranchParameters {
98        fn from(value: ConditionInfo) -> Self {
99            let to_llvm_cond_id = |cond_id: Option<ConditionId>| {
100                cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1)
101            };
102            let ConditionInfo { condition_id, true_next_id, false_next_id } = value;
103            Self {
104                condition_id: to_llvm_cond_id(Some(condition_id)),
105                condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)],
106            }
107        }
108    }
109
110    impl From<DecisionInfo> for DecisionParameters {
111        fn from(info: DecisionInfo) -> Self {
112            let DecisionInfo { bitmap_idx, num_conditions } = info;
113            Self { bitmap_idx, num_conditions }
114        }
115    }
116}
117
118/// A span of source code coordinates to be embedded in coverage metadata.
119///
120/// Must match the layout of `LLVMRustCoverageSpan`.
121#[derive(Clone, Debug)]
122#[repr(C)]
123pub(crate) struct CoverageSpan {
124    /// Local index into the function's local-to-global file ID table.
125    /// The value at that index is itself an index into the coverage filename
126    /// table in the CGU's `__llvm_covmap` section.
127    pub(crate) file_id: u32,
128
129    /// 1-based starting line of the source code span.
130    pub(crate) start_line: u32,
131    /// 1-based starting column of the source code span.
132    pub(crate) start_col: u32,
133    /// 1-based ending line of the source code span.
134    pub(crate) end_line: u32,
135    /// 1-based ending column of the source code span. High bit must be unset.
136    pub(crate) end_col: u32,
137}
138
139/// Holds tables of the various region types in one struct.
140///
141/// Don't pass this struct across FFI; pass the individual region tables as
142/// pointer/length pairs instead.
143///
144/// Each field name has a `_regions` suffix for improved readability after
145/// exhaustive destructing, which ensures that all region types are handled.
146#[derive(Clone, Debug, Default)]
147pub(crate) struct Regions {
148    pub(crate) code_regions: Vec<CodeRegion>,
149    pub(crate) expansion_regions: Vec<ExpansionRegion>,
150    pub(crate) branch_regions: Vec<BranchRegion>,
151    pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>,
152    pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>,
153}
154
155impl Regions {
156    /// Returns true if none of this structure's tables contain any regions.
157    pub(crate) fn has_no_regions(&self) -> bool {
158        let Self {
159            code_regions,
160            expansion_regions,
161            branch_regions,
162            mcdc_branch_regions,
163            mcdc_decision_regions,
164        } = self;
165
166        code_regions.is_empty()
167            && expansion_regions.is_empty()
168            && branch_regions.is_empty()
169            && mcdc_branch_regions.is_empty()
170            && mcdc_decision_regions.is_empty()
171    }
172}
173
174/// Must match the layout of `LLVMRustCoverageCodeRegion`.
175#[derive(Clone, Debug)]
176#[repr(C)]
177pub(crate) struct CodeRegion {
178    pub(crate) cov_span: CoverageSpan,
179    pub(crate) counter: Counter,
180}
181
182/// Must match the layout of `LLVMRustCoverageExpansionRegion`.
183#[derive(Clone, Debug)]
184#[repr(C)]
185pub(crate) struct ExpansionRegion {
186    pub(crate) cov_span: CoverageSpan,
187    pub(crate) expanded_file_id: u32,
188}
189
190/// Must match the layout of `LLVMRustCoverageBranchRegion`.
191#[derive(Clone, Debug)]
192#[repr(C)]
193pub(crate) struct BranchRegion {
194    pub(crate) cov_span: CoverageSpan,
195    pub(crate) true_counter: Counter,
196    pub(crate) false_counter: Counter,
197}
198
199/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
200#[derive(Clone, Debug)]
201#[repr(C)]
202pub(crate) struct MCDCBranchRegion {
203    pub(crate) cov_span: CoverageSpan,
204    pub(crate) true_counter: Counter,
205    pub(crate) false_counter: Counter,
206    pub(crate) mcdc_branch_params: mcdc::BranchParameters,
207}
208
209/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
210#[derive(Clone, Debug)]
211#[repr(C)]
212pub(crate) struct MCDCDecisionRegion {
213    pub(crate) cov_span: CoverageSpan,
214    pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
215}