@@ -65,21 +65,78 @@ class ParentMapContext::ParentMap {
65
65
public:
66
66
ParentVector () = default ;
67
67
explicit ParentVector (size_t N, const DynTypedNode &Value) {
68
- Items .reserve (N);
68
+ SortedAndUnsortedItems .reserve (N);
69
69
for (; N > 0 ; --N)
70
70
push_back (Value);
71
71
}
72
72
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;
74
86
}
75
87
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 ();
78
100
}
79
- llvm::ArrayRef<DynTypedNode> view () const { return Items; }
101
+ llvm::ArrayRef<DynTypedNode> view () {
102
+ ++Budget;
103
+ return SortedAndUnsortedItems;
104
+ }
105
+
80
106
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 ;
83
140
};
84
141
85
142
// / Maps from a node to its parents. This is used for nodes that have
@@ -117,7 +174,7 @@ class ParentMapContext::ParentMap {
117
174
if (I == Map.end ()) {
118
175
return llvm::ArrayRef<DynTypedNode>();
119
176
}
120
- if (const auto *V = dyn_cast<ParentVector *>(I->second )) {
177
+ if (auto *V = dyn_cast<ParentVector *>(I->second )) {
121
178
return V->view ();
122
179
}
123
180
return getSingleDynTypedNodeFromParentMap (I->second );
0 commit comments