@@ -65,21 +65,78 @@ class ParentMapContext::ParentMap {
6565 public:
6666 ParentVector () = default ;
6767 explicit ParentVector (size_t N, const DynTypedNode &Value) {
68- Items .reserve (N);
68+ SortedAndUnsortedItems .reserve (N);
6969 for (; N > 0 ; --N)
7070 push_back (Value);
7171 }
7272 bool contains (const DynTypedNode &Value) {
73- return Seen.contains (Value);
73+ const auto SortBoundary = SortedAndUnsortedItems.begin () + NumSorted;
74+ bool Found = std::binary_search (SortedAndUnsortedItems.begin (),
75+ SortBoundary, Value);
76+ Budget += llvm::bit_width (
77+ static_cast <size_t >(SortBoundary - SortedAndUnsortedItems.begin ()));
78+ if (!Found) {
79+ auto FoundIt =
80+ std::find (SortBoundary, SortedAndUnsortedItems.end (), Value);
81+ Budget += FoundIt - SortBoundary;
82+ Found |= FoundIt != SortedAndUnsortedItems.end ();
83+ }
84+ SortIfWorthwhile ();
85+ return Found;
7486 }
7587 void push_back (const DynTypedNode &Value) {
76- if (!Value.getMemoizationData () || Seen.insert (Value).second )
77- Items.push_back (Value);
88+ ++Budget;
89+ if (!Value.getMemoizationData () || !contains (Value)) {
90+ SortedAndUnsortedItems.push_back (Value);
91+ if (SortedAndUnsortedItems.back () < SortedAndUnsortedItems[NumSorted]) {
92+ // Keep the minimum element in the middle to quickly tell us if
93+ // merging will be necessary
94+ using std::swap;
95+ swap (SortedAndUnsortedItems.back (),
96+ SortedAndUnsortedItems[NumSorted]);
97+ }
98+ }
99+ VerifyInvariant ();
78100 }
79- llvm::ArrayRef<DynTypedNode> view () const { return Items; }
101+ llvm::ArrayRef<DynTypedNode> view () {
102+ ++Budget;
103+ return SortedAndUnsortedItems;
104+ }
105+
80106 private:
81- llvm::SmallVector<DynTypedNode, 2 > Items;
82- llvm::SmallDenseSet<DynTypedNode, 2 > Seen;
107+ void SortIfWorthwhile () {
108+ VerifyInvariant ();
109+ auto SortBoundary = SortedAndUnsortedItems.begin () + NumSorted;
110+ if (SortBoundary != SortedAndUnsortedItems.end ()) {
111+ const size_t NumUnsorted = SortedAndUnsortedItems.end () - SortBoundary;
112+ const size_t SortingCost = NumUnsorted * llvm::bit_width (NumUnsorted);
113+ const bool NeedMerge = SortBoundary != SortedAndUnsortedItems.begin ();
114+ // Assume that the naive implementation would copy these elements.
115+ // This is just an estimate; it's OK if it's wrong.
116+ const size_t MergeCost = SortedAndUnsortedItems.size () + NumUnsorted;
117+ if (Budget >= (NeedMerge ? MergeCost : 0 ) + SortingCost) {
118+ std::sort (SortBoundary, SortedAndUnsortedItems.end ());
119+ if (NeedMerge) {
120+ std::inplace_merge (SortedAndUnsortedItems.begin (), SortBoundary,
121+ SortedAndUnsortedItems.end ());
122+ }
123+ Budget = 0 ;
124+ NumSorted = SortedAndUnsortedItems.size ();
125+ }
126+ }
127+ }
128+
129+ void VerifyInvariant () const {
130+ assert (
131+ !(NumSorted < SortedAndUnsortedItems.size () &&
132+ SortedAndUnsortedItems.back () <
133+ SortedAndUnsortedItems[NumSorted]) &&
134+ " the boundary item must always be the minimum of the unsorted items" );
135+ }
136+
137+ llvm::SmallVector<DynTypedNode, 2 > SortedAndUnsortedItems;
138+ size_t NumSorted = 0 ;
139+ int64_t Budget = 0 ;
83140 };
84141
85142 // / Maps from a node to its parents. This is used for nodes that have
@@ -117,7 +174,7 @@ class ParentMapContext::ParentMap {
117174 if (I == Map.end ()) {
118175 return llvm::ArrayRef<DynTypedNode>();
119176 }
120- if (const auto *V = dyn_cast<ParentVector *>(I->second )) {
177+ if (auto *V = dyn_cast<ParentVector *>(I->second )) {
121178 return V->view ();
122179 }
123180 return getSingleDynTypedNodeFromParentMap (I->second );
0 commit comments