]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/coverage.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / compiler / rustc_middle / src / mir / coverage.rs
1 //! Metadata from source code coverage analysis and instrumentation.
2
3 use rustc_macros::HashStable;
4 use rustc_span::Symbol;
5
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`.
13     #[derive(HashStable)]
14     #[max = 0xFFFF_FFFF]
15     #[debug_format = "ExpressionOperandId({})"]
16     pub struct ExpressionOperandId {
17     }
18 }
19
20 impl ExpressionOperandId {
21     /// An expression operand for a "zero counter", as described in the following references:
22     ///
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>
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! {
35     #[derive(HashStable)]
36     #[max = 0xFFFF_FFFF]
37     #[debug_format = "CounterValueReference({})"]
38     pub struct CounterValueReference {}
39 }
40
41 impl CounterValueReference {
42     /// Counters start at 1 to reserve 0 for ExpressionOperandId::ZERO.
43     pub const START: Self = Self::from_u32(1);
44
45     /// Returns explicitly-requested zero-based version of the counter id, used
46     /// during codegen. LLVM expects zero-based indexes.
47     pub fn zero_based_index(self) -> u32 {
48         let one_based_index = self.as_u32();
49         debug_assert!(one_based_index > 0);
50         one_based_index - 1
51     }
52 }
53
54 rustc_index::newtype_index! {
55     /// InjectedExpressionId.as_u32() converts to ExpressionOperandId.as_u32()
56     ///
57     /// Values descend from u32::MAX.
58     #[derive(HashStable)]
59     #[max = 0xFFFF_FFFF]
60     #[debug_format = "InjectedExpressionId({})"]
61     pub struct InjectedExpressionId {}
62 }
63
64 rustc_index::newtype_index! {
65     /// InjectedExpressionIndex.as_u32() translates to u32::MAX - ExpressionOperandId.as_u32()
66     ///
67     /// Values ascend from 0.
68     #[derive(HashStable)]
69     #[max = 0xFFFF_FFFF]
70     #[debug_format = "InjectedExpressionIndex({})"]
71     pub struct InjectedExpressionIndex {}
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.
78     #[derive(HashStable)]
79     #[max = 0xFFFF_FFFF]
80     #[debug_format = "MappedExpressionIndex({})"]
81     pub struct MappedExpressionIndex {}
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
98 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
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
123     pub fn is_expression(&self) -> bool {
124         matches!(self, Self::Expression { .. })
125     }
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(),
138                 match op {
139                     Op::Add => "+",
140                     Op::Subtract => "-",
141                 },
142                 rhs.index(),
143             ),
144             Unreachable => write!(fmt, "Unreachable"),
145         }
146     }
147 }
148
149 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
150 #[derive(TypeFoldable, TypeVisitable)]
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
169 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
170 #[derive(TypeFoldable, TypeVisitable)]
171 pub enum Op {
172     Subtract,
173     Add,
174 }
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 }