@@ -60,6 +60,30 @@ class ParentMapContext::ParentMap {
60
60
61
61
template <typename , typename ...> friend struct ::MatchParents;
62
62
63
+ template <class T > struct IndirectDenseMapInfo {
64
+ using Ptr = T *;
65
+ using Base = llvm::DenseMapInfo<std::remove_cv_t <T>>;
66
+ static inline Ptr getEmptyKey () {
67
+ return static_cast <Ptr >(llvm::DenseMapInfo<void *>::getEmptyKey ());
68
+ }
69
+ static inline Ptr getTombstoneKey () {
70
+ return static_cast <Ptr >(llvm::DenseMapInfo<void *>::getTombstoneKey ());
71
+ }
72
+ static unsigned getHashValue (Ptr Val) {
73
+ return Val == getEmptyKey () || Val == getTombstoneKey ()
74
+ ? 0
75
+ : Base::getHashValue (*Val);
76
+ }
77
+ static bool isEqual (Ptr LHS, Ptr RHS) {
78
+ if (LHS == getEmptyKey () || LHS == getTombstoneKey () ||
79
+ RHS == getEmptyKey () || RHS == getTombstoneKey ()) {
80
+ return LHS == RHS;
81
+ }
82
+ return Base::isEqual (*LHS, *RHS);
83
+ }
84
+ };
85
+ using MapInfo = IndirectDenseMapInfo<const DynTypedNode>;
86
+
63
87
// / Contains parents of a node.
64
88
class ParentVector {
65
89
public:
@@ -70,16 +94,38 @@ class ParentMapContext::ParentMap {
70
94
push_back (Value);
71
95
}
72
96
bool contains (const DynTypedNode &Value) {
73
- return Seen.contains (Value);
97
+ assert (Value.getMemoizationData ());
98
+ bool Found = FragileLazySeenCache.contains (&Value);
99
+ while (!Found && ItemsProcessed < Items.size ()) {
100
+ const auto It = Items.begin () + ItemsProcessed;
101
+ Found = MapInfo::isEqual (&*It, &Value);
102
+ FragileLazySeenCache.insert (&*It);
103
+ ++ItemsProcessed;
104
+ }
105
+ return Found;
74
106
}
75
107
void push_back (const DynTypedNode &Value) {
76
- if (!Value.getMemoizationData () || Seen.insert (Value).second )
108
+ if (!Value.getMemoizationData () || !contains (Value)) {
109
+ const size_t OldCapacity = Items.capacity ();
77
110
Items.push_back (Value);
111
+ if (OldCapacity != Items.capacity ()) {
112
+ // Pointers are invalidated; remove them.
113
+ ItemsProcessed = 0 ;
114
+ // Free memory to avoid doubling peak memory usage during rehashing.
115
+ FragileLazySeenCache.clear ();
116
+ }
117
+ }
78
118
}
79
119
llvm::ArrayRef<DynTypedNode> view () const { return Items; }
80
120
private:
121
+ // BE CAREFUL. Pointers into this container are stored in the
122
+ // `FragileLazySeenCache` set below.
81
123
llvm::SmallVector<DynTypedNode, 2 > Items;
82
- llvm::SmallDenseSet<DynTypedNode, 2 > Seen;
124
+ // This cache is fragile because it contains pointers that are invalidated
125
+ // when the vector capacity changes.
126
+ llvm::SmallDenseSet<const DynTypedNode *, 2 , MapInfo> FragileLazySeenCache;
127
+ // Lazily tracks which items have been processed for the cache.
128
+ size_t ItemsProcessed = 0 ;
83
129
};
84
130
85
131
// / Maps from a node to its parents. This is used for nodes that have
0 commit comments