@@ -60,6 +60,30 @@ 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+ using MapInfo = IndirectDenseMapInfo<const DynTypedNode>;
86+
6387 // / Contains parents of a node.
6488 class ParentVector {
6589 public:
@@ -70,16 +94,38 @@ class ParentMapContext::ParentMap {
7094 push_back (Value);
7195 }
7296 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;
74106 }
75107 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 ();
77110 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+ }
78118 }
79119 llvm::ArrayRef<DynTypedNode> view () const { return Items; }
80120 private:
121+ // BE CAREFUL. Pointers into this container are stored in the
122+ // `FragileLazySeenCache` set below.
81123 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 ;
83129 };
84130
85131 // / Maps from a node to its parents. This is used for nodes that have
0 commit comments