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) branch_regions: Vec<BranchRegion>,
150    pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>,
151    pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>,
152}
153
154impl Regions {
155    /// Returns true if none of this structure's tables contain any regions.
156    pub(crate) fn has_no_regions(&self) -> bool {
157        let Self { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
158            self;
159
160        code_regions.is_empty()
161            && branch_regions.is_empty()
162            && mcdc_branch_regions.is_empty()
163            && mcdc_decision_regions.is_empty()
164    }
165}
166
167/// Must match the layout of `LLVMRustCoverageCodeRegion`.
168#[derive(Clone, Debug)]
169#[repr(C)]
170pub(crate) struct CodeRegion {
171    pub(crate) cov_span: CoverageSpan,
172    pub(crate) counter: Counter,
173}
174
175/// Must match the layout of `LLVMRustCoverageBranchRegion`.
176#[derive(Clone, Debug)]
177#[repr(C)]
178pub(crate) struct BranchRegion {
179    pub(crate) cov_span: CoverageSpan,
180    pub(crate) true_counter: Counter,
181    pub(crate) false_counter: Counter,
182}
183
184/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
185#[derive(Clone, Debug)]
186#[repr(C)]
187pub(crate) struct MCDCBranchRegion {
188    pub(crate) cov_span: CoverageSpan,
189    pub(crate) true_counter: Counter,
190    pub(crate) false_counter: Counter,
191    pub(crate) mcdc_branch_params: mcdc::BranchParameters,
192}
193
194/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
195#[derive(Clone, Debug)]
196#[repr(C)]
197pub(crate) struct MCDCDecisionRegion {
198    pub(crate) cov_span: CoverageSpan,
199    pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
200}