|
1 | 1 | use rustc_data_structures::captures::Captures; |
2 | | -use rustc_data_structures::fx::FxIndexSet; |
3 | | -use rustc_index::bit_set::BitSet; |
4 | 2 | use rustc_middle::mir::coverage::{ |
5 | | - CounterId, CovTerm, CoverageIdsInfo, Expression, ExpressionId, FunctionCoverageInfo, Mapping, |
6 | | - MappingKind, Op, SourceRegion, |
| 3 | + CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op, |
| 4 | + SourceRegion, |
7 | 5 | }; |
8 | 6 | use rustc_middle::ty::Instance; |
9 | 7 | use tracing::debug; |
@@ -55,92 +53,17 @@ impl<'tcx> FunctionCoverageCollector<'tcx> { |
55 | 53 | Self { function_coverage_info, ids_info, is_used } |
56 | 54 | } |
57 | 55 |
|
58 | | - /// Identify expressions that will always have a value of zero, and note |
59 | | - /// their IDs in [`ZeroExpressions`]. Mappings that refer to a zero expression |
60 | | - /// can instead become mappings to a constant zero value. |
61 | | - /// |
62 | | - /// This method mainly exists to preserve the simplifications that were |
63 | | - /// already being performed by the Rust-side expression renumbering, so that |
64 | | - /// the resulting coverage mappings don't get worse. |
65 | | - fn identify_zero_expressions(&self) -> ZeroExpressions { |
66 | | - // The set of expressions that either were optimized out entirely, or |
67 | | - // have zero as both of their operands, and will therefore always have |
68 | | - // a value of zero. Other expressions that refer to these as operands |
69 | | - // can have those operands replaced with `CovTerm::Zero`. |
70 | | - let mut zero_expressions = ZeroExpressions::default(); |
71 | | - |
72 | | - // Simplify a copy of each expression based on lower-numbered expressions, |
73 | | - // and then update the set of always-zero expressions if necessary. |
74 | | - // (By construction, expressions can only refer to other expressions |
75 | | - // that have lower IDs, so one pass is sufficient.) |
76 | | - for (id, expression) in self.function_coverage_info.expressions.iter_enumerated() { |
77 | | - if !self.is_used || !self.ids_info.expressions_seen.contains(id) { |
78 | | - // If an expression was not seen, it must have been optimized away, |
79 | | - // so any operand that refers to it can be replaced with zero. |
80 | | - zero_expressions.insert(id); |
81 | | - continue; |
82 | | - } |
83 | | - |
84 | | - // We don't need to simplify the actual expression data in the |
85 | | - // expressions list; we can just simplify a temporary copy and then |
86 | | - // use that to update the set of always-zero expressions. |
87 | | - let Expression { mut lhs, op, mut rhs } = *expression; |
88 | | - |
89 | | - // If an expression has an operand that is also an expression, the |
90 | | - // operand's ID must be strictly lower. This is what lets us find |
91 | | - // all zero expressions in one pass. |
92 | | - let assert_operand_expression_is_lower = |operand_id: ExpressionId| { |
93 | | - assert!( |
94 | | - operand_id < id, |
95 | | - "Operand {operand_id:?} should be less than {id:?} in {expression:?}", |
96 | | - ) |
97 | | - }; |
98 | | - |
99 | | - // If an operand refers to a counter or expression that is always |
100 | | - // zero, then that operand can be replaced with `CovTerm::Zero`. |
101 | | - let maybe_set_operand_to_zero = |operand: &mut CovTerm| { |
102 | | - if let CovTerm::Expression(id) = *operand { |
103 | | - assert_operand_expression_is_lower(id); |
104 | | - } |
105 | | - |
106 | | - if is_zero_term(&self.ids_info.counters_seen, &zero_expressions, *operand) { |
107 | | - *operand = CovTerm::Zero; |
108 | | - } |
109 | | - }; |
110 | | - maybe_set_operand_to_zero(&mut lhs); |
111 | | - maybe_set_operand_to_zero(&mut rhs); |
112 | | - |
113 | | - // Coverage counter values cannot be negative, so if an expression |
114 | | - // involves subtraction from zero, assume that its RHS must also be zero. |
115 | | - // (Do this after simplifications that could set the LHS to zero.) |
116 | | - if lhs == CovTerm::Zero && op == Op::Subtract { |
117 | | - rhs = CovTerm::Zero; |
118 | | - } |
119 | | - |
120 | | - // After the above simplifications, if both operands are zero, then |
121 | | - // we know that this expression is always zero too. |
122 | | - if lhs == CovTerm::Zero && rhs == CovTerm::Zero { |
123 | | - zero_expressions.insert(id); |
124 | | - } |
125 | | - } |
126 | | - |
127 | | - zero_expressions |
128 | | - } |
129 | | - |
130 | 56 | pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> { |
131 | | - let zero_expressions = self.identify_zero_expressions(); |
132 | 57 | let FunctionCoverageCollector { function_coverage_info, ids_info, is_used, .. } = self; |
133 | 58 |
|
134 | | - FunctionCoverage { function_coverage_info, ids_info, is_used, zero_expressions } |
| 59 | + FunctionCoverage { function_coverage_info, ids_info, is_used } |
135 | 60 | } |
136 | 61 | } |
137 | 62 |
|
138 | 63 | pub(crate) struct FunctionCoverage<'tcx> { |
139 | 64 | pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo, |
140 | 65 | ids_info: &'tcx CoverageIdsInfo, |
141 | 66 | is_used: bool, |
142 | | - |
143 | | - zero_expressions: ZeroExpressions, |
144 | 67 | } |
145 | 68 |
|
146 | 69 | impl<'tcx> FunctionCoverage<'tcx> { |
@@ -195,37 +118,6 @@ impl<'tcx> FunctionCoverage<'tcx> { |
195 | 118 | } |
196 | 119 |
|
197 | 120 | fn is_zero_term(&self, term: CovTerm) -> bool { |
198 | | - !self.is_used || is_zero_term(&self.ids_info.counters_seen, &self.zero_expressions, term) |
199 | | - } |
200 | | -} |
201 | | - |
202 | | -/// Set of expression IDs that are known to always evaluate to zero. |
203 | | -/// Any mapping or expression operand that refers to these expressions can have |
204 | | -/// that reference replaced with a constant zero value. |
205 | | -#[derive(Default)] |
206 | | -struct ZeroExpressions(FxIndexSet<ExpressionId>); |
207 | | - |
208 | | -impl ZeroExpressions { |
209 | | - fn insert(&mut self, id: ExpressionId) { |
210 | | - self.0.insert(id); |
211 | | - } |
212 | | - |
213 | | - fn contains(&self, id: ExpressionId) -> bool { |
214 | | - self.0.contains(&id) |
215 | | - } |
216 | | -} |
217 | | - |
218 | | -/// Returns `true` if the given term is known to have a value of zero, taking |
219 | | -/// into account knowledge of which counters are unused and which expressions |
220 | | -/// are always zero. |
221 | | -fn is_zero_term( |
222 | | - counters_seen: &BitSet<CounterId>, |
223 | | - zero_expressions: &ZeroExpressions, |
224 | | - term: CovTerm, |
225 | | -) -> bool { |
226 | | - match term { |
227 | | - CovTerm::Zero => true, |
228 | | - CovTerm::Counter(id) => !counters_seen.contains(id), |
229 | | - CovTerm::Expression(id) => zero_expressions.contains(id), |
| 121 | + !self.is_used || self.ids_info.is_zero_term(term) |
230 | 122 | } |
231 | 123 | } |
0 commit comments