]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/coverage.rs
Auto merge of #92041 - Aaron1011:remove-speculative-evaluation, r=jackh726
[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::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 }