]>
Commit | Line | Data |
---|---|---|
1 | //! Metadata from source code coverage analysis and instrumentation. | |
2 | ||
3 | use rustc_macros::HashStable; | |
4 | use rustc_span::Symbol; | |
5 | ||
6 | use std::cmp::Ord; | |
7 | use std::fmt::{self, Debug, Formatter}; | |
8 | ||
9 | rustc_index::newtype_index! { | |
10 | /// An ExpressionOperandId value is assigned directly from either a | |
11 | /// CounterValueReference.as_u32() (which ascend from 1) or an ExpressionOperandId.as_u32() | |
12 | /// (which _*descend*_ from u32::MAX). Id value `0` (zero) represents a virtual counter with a | |
13 | /// constant value of `0`. | |
14 | pub struct ExpressionOperandId { | |
15 | derive [HashStable] | |
16 | DEBUG_FORMAT = "ExpressionOperandId({})", | |
17 | MAX = 0xFFFF_FFFF, | |
18 | } | |
19 | } | |
20 | ||
21 | impl ExpressionOperandId { | |
22 | /// An expression operand for a "zero counter", as described in the following references: | |
23 | /// | |
24 | /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter> | |
25 | /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag> | |
26 | /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions> | |
27 | /// | |
28 | /// This operand can be used to count two or more separate code regions with a single counter, | |
29 | /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for | |
30 | /// one of the code regions, and inserting `CounterExpression`s ("add ZERO to the counter") in | |
31 | /// the coverage map for the other code regions. | |
32 | pub const ZERO: Self = Self::from_u32(0); | |
33 | } | |
34 | ||
35 | rustc_index::newtype_index! { | |
36 | pub struct CounterValueReference { | |
37 | derive [HashStable] | |
38 | DEBUG_FORMAT = "CounterValueReference({})", | |
39 | MAX = 0xFFFF_FFFF, | |
40 | } | |
41 | } | |
42 | ||
43 | impl CounterValueReference { | |
44 | /// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO. | |
45 | pub const START: Self = Self::from_u32(1); | |
46 | ||
47 | /// Returns explicitly-requested zero-based version of the counter id, used | |
48 | /// during codegen. LLVM expects zero-based indexes. | |
49 | pub fn zero_based_index(&self) -> u32 { | |
50 | let one_based_index = self.as_u32(); | |
51 | debug_assert!(one_based_index > 0); | |
52 | one_based_index - 1 | |
53 | } | |
54 | } | |
55 | ||
56 | rustc_index::newtype_index! { | |
57 | /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32() | |
58 | /// | |
59 | /// Values descend from u32::MAX. | |
60 | pub struct InjectedExpressionId { | |
61 | derive [HashStable] | |
62 | DEBUG_FORMAT = "InjectedExpressionId({})", | |
63 | MAX = 0xFFFF_FFFF, | |
64 | } | |
65 | } | |
66 | ||
67 | rustc_index::newtype_index! { | |
68 | /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32() | |
69 | /// | |
70 | /// Values ascend from 0. | |
71 | pub struct InjectedExpressionIndex { | |
72 | derive [HashStable] | |
73 | DEBUG_FORMAT = "InjectedExpressionIndex({})", | |
74 | MAX = 0xFFFF_FFFF, | |
75 | } | |
76 | } | |
77 | ||
78 | rustc_index::newtype_index! { | |
79 | /// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their | |
80 | /// array position in the LLVM coverage map "Expressions" array, which is assembled during the | |
81 | /// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s. | |
82 | pub struct MappedExpressionIndex { | |
83 | derive [HashStable] | |
84 | DEBUG_FORMAT = "MappedExpressionIndex({})", | |
85 | MAX = 0xFFFF_FFFF, | |
86 | } | |
87 | } | |
88 | ||
89 | impl From<CounterValueReference> for ExpressionOperandId { | |
90 | #[inline] | |
91 | fn from(v: CounterValueReference) -> ExpressionOperandId { | |
92 | ExpressionOperandId::from(v.as_u32()) | |
93 | } | |
94 | } | |
95 | ||
96 | impl From<InjectedExpressionId> for ExpressionOperandId { | |
97 | #[inline] | |
98 | fn from(v: InjectedExpressionId) -> ExpressionOperandId { | |
99 | ExpressionOperandId::from(v.as_u32()) | |
100 | } | |
101 | } | |
102 | ||
103 | #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] | |
104 | pub enum CoverageKind { | |
105 | Counter { | |
106 | function_source_hash: u64, | |
107 | id: CounterValueReference, | |
108 | }, | |
109 | Expression { | |
110 | id: InjectedExpressionId, | |
111 | lhs: ExpressionOperandId, | |
112 | op: Op, | |
113 | rhs: ExpressionOperandId, | |
114 | }, | |
115 | Unreachable, | |
116 | } | |
117 | ||
118 | impl CoverageKind { | |
119 | pub fn as_operand_id(&self) -> ExpressionOperandId { | |
120 | use CoverageKind::*; | |
121 | match *self { | |
122 | Counter { id, .. } => ExpressionOperandId::from(id), | |
123 | Expression { id, .. } => ExpressionOperandId::from(id), | |
124 | Unreachable => bug!("Unreachable coverage cannot be part of an expression"), | |
125 | } | |
126 | } | |
127 | ||
128 | pub fn is_expression(&self) -> bool { | |
129 | matches!(self, Self::Expression { .. }) | |
130 | } | |
131 | } | |
132 | ||
133 | impl Debug for CoverageKind { | |
134 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
135 | use CoverageKind::*; | |
136 | match self { | |
137 | Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), | |
138 | Expression { id, lhs, op, rhs } => write!( | |
139 | fmt, | |
140 | "Expression({:?}) = {} {} {}", | |
141 | id.index(), | |
142 | lhs.index(), | |
143 | if *op == Op::Add { "+" } else { "-" }, | |
144 | rhs.index(), | |
145 | ), | |
146 | Unreachable => write!(fmt, "Unreachable"), | |
147 | } | |
148 | } | |
149 | } | |
150 | ||
151 | #[derive( | |
152 | Clone, | |
153 | TyEncodable, | |
154 | TyDecodable, | |
155 | Hash, | |
156 | HashStable, | |
157 | TypeFoldable, | |
158 | PartialEq, | |
159 | Eq, | |
160 | PartialOrd, | |
161 | Ord | |
162 | )] | |
163 | pub struct CodeRegion { | |
164 | pub file_name: Symbol, | |
165 | pub start_line: u32, | |
166 | pub start_col: u32, | |
167 | pub end_line: u32, | |
168 | pub end_col: u32, | |
169 | } | |
170 | ||
171 | impl Debug for CodeRegion { | |
172 | fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { | |
173 | write!( | |
174 | fmt, | |
175 | "{}:{}:{} - {}:{}", | |
176 | self.file_name, self.start_line, self.start_col, self.end_line, self.end_col | |
177 | ) | |
178 | } | |
179 | } | |
180 | ||
181 | #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)] | |
182 | pub enum Op { | |
183 | Subtract, | |
184 | Add, | |
185 | } | |
186 | ||
187 | impl Op { | |
188 | pub fn is_add(&self) -> bool { | |
189 | matches!(self, Self::Add) | |
190 | } | |
191 | ||
192 | pub fn is_subtract(&self) -> bool { | |
193 | matches!(self, Self::Subtract) | |
194 | } | |
195 | } |