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