|
1 | 1 | use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
|
2 | 2 |
|
| 3 | +use rustc_data_structures::fx::FxIndexSet; |
3 | 4 | use rustc_index::{IndexSlice, IndexVec};
|
4 | 5 | use rustc_middle::bug;
|
5 | 6 | use rustc_middle::mir::coverage::{
|
@@ -128,6 +129,58 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
128 | 129 | self.unreachable_regions.push(region)
|
129 | 130 | }
|
130 | 131 |
|
| 132 | + /// Perform some simplifications to make the final coverage mappings |
| 133 | + /// slightly smaller. |
| 134 | + /// |
| 135 | + /// This method mainly exists to preserve the simplifications that were |
| 136 | + /// already being performed by the Rust-side expression renumbering, so that |
| 137 | + /// the resulting coverage mappings don't get worse. |
| 138 | + pub(crate) fn simplify_expressions(&mut self) { |
| 139 | + // The set of expressions that either were optimized out entirely, or |
| 140 | + // have zero as both of their operands, and will therefore always have |
| 141 | + // a value of zero. Other expressions that refer to these as operands |
| 142 | + // can have those operands replaced with `Operand::Zero`. |
| 143 | + let mut zero_expressions = FxIndexSet::default(); |
| 144 | + |
| 145 | + // For each expression, perform simplifications based on lower-numbered |
| 146 | + // expressions, and then update the set of always-zero expressions if |
| 147 | + // necessary. |
| 148 | + // (By construction, expressions can only refer to other expressions |
| 149 | + // that have lower IDs, so one simplification pass is sufficient.) |
| 150 | + for (id, maybe_expression) in self.expressions.iter_enumerated_mut() { |
| 151 | + let Some(expression) = maybe_expression else { |
| 152 | + // If an expression is missing, it must have been optimized away, |
| 153 | + // so any operand that refers to it can be replaced with zero. |
| 154 | + zero_expressions.insert(id); |
| 155 | + continue; |
| 156 | + }; |
| 157 | + |
| 158 | + // If an operand refers to an expression that is always zero, then |
| 159 | + // that operand can be replaced with `Operand::Zero`. |
| 160 | + let maybe_set_operand_to_zero = |operand: &mut Operand| match &*operand { |
| 161 | + Operand::Expression(id) if zero_expressions.contains(id) => { |
| 162 | + *operand = Operand::Zero; |
| 163 | + } |
| 164 | + _ => (), |
| 165 | + }; |
| 166 | + maybe_set_operand_to_zero(&mut expression.lhs); |
| 167 | + maybe_set_operand_to_zero(&mut expression.rhs); |
| 168 | + |
| 169 | + // Coverage counter values cannot be negative, so if an expression |
| 170 | + // involves subtraction from zero, assume that its RHS must also be zero. |
| 171 | + // (Do this after simplifications that could set the LHS to zero.) |
| 172 | + if let Expression { lhs: Operand::Zero, op: Op::Subtract, .. } = expression { |
| 173 | + expression.rhs = Operand::Zero; |
| 174 | + } |
| 175 | + |
| 176 | + // After the above simplifications, if both operands are zero, then |
| 177 | + // we know that this expression is always zero too. |
| 178 | + if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression { |
| 179 | + zero_expressions.insert(id); |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | + |
131 | 184 | /// Return the source hash, generated from the HIR node structure, and used to indicate whether
|
132 | 185 | /// or not the source code structure changed between different compilations.
|
133 | 186 | pub fn source_hash(&self) -> u64 {
|
|
0 commit comments