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}