@@ -60,6 +60,29 @@ class ParentMapContext::ParentMap {
6060
6161 template <typename , typename ...> friend struct ::MatchParents;
6262
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+
6386 // / Contains parents of a node.
6487 class ParentVector {
6588 public:
@@ -70,16 +93,38 @@ class ParentMapContext::ParentMap {
7093 push_back (Value);
7194 }
7295 bool contains (const DynTypedNode &Value) {
73- return Seen.contains (Value);
96+ assert (Value.getMemoizationData ());
97+ bool found = FragileLazySeenCache.contains (&Value);
98+ while (!found && ItemsProcessed < Items.size ()) {
99+ found |= FragileLazySeenCache.insert (&Items[ItemsProcessed]).second ;
100+ ++ItemsProcessed;
101+ }
102+ return found;
74103 }
75104 void push_back (const DynTypedNode &Value) {
76- if (!Value.getMemoizationData () || Seen.insert (Value).second )
105+ if (!Value.getMemoizationData () || !contains (Value)) {
106+ const size_t OldCapacity = Items.capacity ();
77107 Items.push_back (Value);
108+ if (OldCapacity != Items.capacity ()) {
109+ // Pointers are invalidated; remove them.
110+ ItemsProcessed = 0 ;
111+ // Free memory to avoid doubling peak memory usage during rehashing
112+ FragileLazySeenCache.clear ();
113+ }
114+ }
78115 }
79116 llvm::ArrayRef<DynTypedNode> view () const { return Items; }
80117 private:
118+ // BE CAREFUL. Pointers into this container are stored in the
119+ // `FragileLazySeenCache` set below.
81120 llvm::SmallVector<DynTypedNode, 2 > Items;
82- llvm::SmallDenseSet<DynTypedNode, 2 > Seen;
121+ // This cache is fragile because it contains pointers that are invalidated
122+ // when the vector capacity changes.
123+ llvm::SmallDenseSet<const DynTypedNode *, 2 ,
124+ IndirectDenseMapInfo<const DynTypedNode>>
125+ FragileLazySeenCache;
126+ // Lazily tracks which items have been processed for the cache.
127+ size_t ItemsProcessed = 0 ;
83128 };
84129
85130 // / Maps from a node to its parents. This is used for nodes that have
0 commit comments