@@ -11,7 +11,7 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverage
11
11
12
12
/// The coverage counter or counter expression associated with a particular
13
13
/// BCB node or BCB edge.
14
- #[ derive( Clone , Copy ) ]
14
+ #[ derive( Clone , Copy , PartialEq , Eq , Hash ) ]
15
15
pub ( super ) enum BcbCounter {
16
16
Counter { id : CounterId } ,
17
17
Expression { id : ExpressionId } ,
@@ -35,7 +35,7 @@ impl Debug for BcbCounter {
35
35
}
36
36
}
37
37
38
- #[ derive( Debug ) ]
38
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
39
39
struct BcbExpression {
40
40
lhs : BcbCounter ,
41
41
op : Op ,
@@ -63,9 +63,13 @@ pub(super) struct CoverageCounters {
63
63
/// We currently don't iterate over this map, but if we do in the future,
64
64
/// switch it back to `FxIndexMap` to avoid query stability hazards.
65
65
bcb_edge_counters : FxHashMap < ( BasicCoverageBlock , BasicCoverageBlock ) , BcbCounter > ,
66
+
66
67
/// Table of expression data, associating each expression ID with its
67
68
/// corresponding operator (+ or -) and its LHS/RHS operands.
68
69
expressions : IndexVec < ExpressionId , BcbExpression > ,
70
+ /// Remember expressions that have already been created (or simplified),
71
+ /// so that we don't create unnecessary duplicates.
72
+ expressions_memo : FxHashMap < BcbExpression , BcbCounter > ,
69
73
}
70
74
71
75
impl CoverageCounters {
@@ -83,6 +87,7 @@ impl CoverageCounters {
83
87
bcb_counters : IndexVec :: from_elem_n ( None , num_bcbs) ,
84
88
bcb_edge_counters : FxHashMap :: default ( ) ,
85
89
expressions : IndexVec :: new ( ) ,
90
+ expressions_memo : FxHashMap :: default ( ) ,
86
91
} ;
87
92
88
93
MakeBcbCounters :: new ( & mut this, basic_coverage_blocks)
@@ -97,7 +102,20 @@ impl CoverageCounters {
97
102
}
98
103
99
104
fn make_expression ( & mut self , lhs : BcbCounter , op : Op , rhs : BcbCounter ) -> BcbCounter {
100
- let id = self . expressions . push ( BcbExpression { lhs, op, rhs } ) ;
105
+ let new_expr = BcbExpression { lhs, op, rhs } ;
106
+ * self
107
+ . expressions_memo
108
+ . entry ( new_expr)
109
+ . or_insert_with ( || Self :: make_expression_inner ( & mut self . expressions , new_expr) )
110
+ }
111
+
112
+ /// This is an associated function so that we can call it while borrowing
113
+ /// `&mut self.expressions_memo`.
114
+ fn make_expression_inner (
115
+ expressions : & mut IndexVec < ExpressionId , BcbExpression > ,
116
+ new_expr : BcbExpression ,
117
+ ) -> BcbCounter {
118
+ let id = expressions. push ( new_expr) ;
101
119
BcbCounter :: Expression { id }
102
120
}
103
121
0 commit comments