mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-09 05:13:01 +00:00
Make ImmutableMap/ImmutableSet quicker by only canonicalizing the tree after an
Add or Remove operation complete, and not while building the intermediate tree. This trades a little bit more memory usage for less accesses to the FoldingSet. On a benchmark for the clang static analyzer, this shaves off another 13% of execution time when using field/array sensitivity. llvm-svn: 80955
This commit is contained in:
parent
23700a97d2
commit
e4f2f7f6b2
@ -90,12 +90,13 @@ public:
|
|||||||
ImmutableMap GetEmptyMap() { return ImmutableMap(F.GetEmptyTree()); }
|
ImmutableMap GetEmptyMap() { return ImmutableMap(F.GetEmptyTree()); }
|
||||||
|
|
||||||
ImmutableMap Add(ImmutableMap Old, key_type_ref K, data_type_ref D) {
|
ImmutableMap Add(ImmutableMap Old, key_type_ref K, data_type_ref D) {
|
||||||
return ImmutableMap(F.Add(Old.Root,
|
TreeTy *T = F.Add(Old.Root, std::make_pair<key_type,data_type>(K,D));
|
||||||
std::make_pair<key_type,data_type>(K,D)));
|
return ImmutableMap(F.GetCanonicalTree(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmutableMap Remove(ImmutableMap Old, key_type_ref K) {
|
ImmutableMap Remove(ImmutableMap Old, key_type_ref K) {
|
||||||
return ImmutableMap(F.Remove(Old.Root,K));
|
TreeTy *T = F.Remove(Old.Root,K);
|
||||||
|
return ImmutableMap(F.GetCanonicalTree(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -432,57 +432,9 @@ private:
|
|||||||
//===--------------------------------------------------===//
|
//===--------------------------------------------------===//
|
||||||
|
|
||||||
TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) {
|
TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) {
|
||||||
// Search the FoldingSet bucket for a Tree with the same digest.
|
|
||||||
FoldingSetNodeID ID;
|
|
||||||
unsigned digest = TreeTy::ComputeDigest(L, R, V);
|
|
||||||
ID.AddInteger(digest);
|
|
||||||
unsigned hash = ID.ComputeHash();
|
|
||||||
|
|
||||||
typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash);
|
|
||||||
typename CacheTy::bucket_iterator E = Cache.bucket_end(hash);
|
|
||||||
|
|
||||||
for (; I != E; ++I) {
|
|
||||||
TreeTy* T = &*I;
|
|
||||||
|
|
||||||
if (T->ComputeDigest() != digest)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// We found a collision. Perform a comparison of Contents('T')
|
|
||||||
// with Contents('L')+'V'+Contents('R').
|
|
||||||
typename TreeTy::iterator TI = T->begin(), TE = T->end();
|
|
||||||
|
|
||||||
// First compare Contents('L') with the (initial) contents of T.
|
|
||||||
if (!CompareTreeWithSection(L, TI, TE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Now compare the new data element.
|
|
||||||
if (TI == TE || !TI->ElementEqual(V))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
++TI;
|
|
||||||
|
|
||||||
// Now compare the remainder of 'T' with 'R'.
|
|
||||||
if (!CompareTreeWithSection(R, TI, TE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (TI != TE)
|
|
||||||
continue; // Contents('R') did not match suffix of 'T'.
|
|
||||||
|
|
||||||
// Trees did match! Return 'T'.
|
|
||||||
return T;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No tree with the contents: Contents('L')+'V'+Contents('R').
|
|
||||||
// Create it. Allocate the new tree node and insert it into the cache.
|
|
||||||
BumpPtrAllocator& A = getAllocator();
|
BumpPtrAllocator& A = getAllocator();
|
||||||
TreeTy* T = (TreeTy*) A.Allocate<TreeTy>();
|
TreeTy* T = (TreeTy*) A.Allocate<TreeTy>();
|
||||||
new (T) TreeTy(L,R,V,IncrementHeight(L,R));
|
new (T) TreeTy(L,R,V,IncrementHeight(L,R));
|
||||||
|
|
||||||
// We do not insert 'T' into the FoldingSet here. This is because
|
|
||||||
// this tree is still mutable and things may get rebalanced.
|
|
||||||
// Because our digest is associative and based on the contents of
|
|
||||||
// the set, this should hopefully not cause any strange bugs.
|
|
||||||
// 'T' is inserted by 'MarkImmutable'.
|
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,12 +567,56 @@ private:
|
|||||||
T->MarkImmutable();
|
T->MarkImmutable();
|
||||||
MarkImmutable(Left(T));
|
MarkImmutable(Left(T));
|
||||||
MarkImmutable(Right(T));
|
MarkImmutable(Right(T));
|
||||||
|
}
|
||||||
|
|
||||||
// Now that the node is immutable it can safely be inserted
|
public:
|
||||||
// into the node cache.
|
TreeTy *GetCanonicalTree(TreeTy *TNew) {
|
||||||
llvm::FoldingSetNodeID ID;
|
if (!TNew)
|
||||||
ID.AddInteger(T->ComputeDigest());
|
return NULL;
|
||||||
Cache.InsertNode(T, (void*) &*Cache.bucket_end(ID.ComputeHash()));
|
|
||||||
|
// Search the FoldingSet bucket for a Tree with the same digest.
|
||||||
|
FoldingSetNodeID ID;
|
||||||
|
unsigned digest = TNew->ComputeDigest();
|
||||||
|
ID.AddInteger(digest);
|
||||||
|
unsigned hash = ID.ComputeHash();
|
||||||
|
|
||||||
|
typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash);
|
||||||
|
typename CacheTy::bucket_iterator E = Cache.bucket_end(hash);
|
||||||
|
|
||||||
|
for (; I != E; ++I) {
|
||||||
|
TreeTy *T = &*I;
|
||||||
|
|
||||||
|
if (T->ComputeDigest() != digest)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We found a collision. Perform a comparison of Contents('T')
|
||||||
|
// with Contents('L')+'V'+Contents('R').
|
||||||
|
typename TreeTy::iterator TI = T->begin(), TE = T->end();
|
||||||
|
|
||||||
|
// First compare Contents('L') with the (initial) contents of T.
|
||||||
|
if (!CompareTreeWithSection(TNew->getLeft(), TI, TE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Now compare the new data element.
|
||||||
|
if (TI == TE || !TI->ElementEqual(TNew->getValue()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
++TI;
|
||||||
|
|
||||||
|
// Now compare the remainder of 'T' with 'R'.
|
||||||
|
if (!CompareTreeWithSection(TNew->getRight(), TI, TE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TI != TE)
|
||||||
|
continue; // Contents('R') did not match suffix of 'T'.
|
||||||
|
|
||||||
|
// Trees did match! Return 'T'.
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'TNew' is the only tree of its kind. Return it.
|
||||||
|
Cache.InsertNode(TNew, (void*) &*Cache.bucket_end(hash));
|
||||||
|
return TNew;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -940,7 +936,7 @@ public:
|
|||||||
typedef ImutAVLTree<ValInfo> TreeTy;
|
typedef ImutAVLTree<ValInfo> TreeTy;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TreeTy* Root;
|
TreeTy *Root;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructs a set from a pointer to a tree root. In general one
|
/// Constructs a set from a pointer to a tree root. In general one
|
||||||
@ -969,7 +965,7 @@ public:
|
|||||||
/// The memory allocated to represent the set is released when the
|
/// The memory allocated to represent the set is released when the
|
||||||
/// factory object that created the set is destroyed.
|
/// factory object that created the set is destroyed.
|
||||||
ImmutableSet Add(ImmutableSet Old, value_type_ref V) {
|
ImmutableSet Add(ImmutableSet Old, value_type_ref V) {
|
||||||
return ImmutableSet(F.Add(Old.Root,V));
|
return ImmutableSet(F.GetCanonicalTree(F.Add(Old.Root,V)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove - Creates a new immutable set that contains all of the values
|
/// Remove - Creates a new immutable set that contains all of the values
|
||||||
@ -980,7 +976,7 @@ public:
|
|||||||
/// The memory allocated to represent the set is released when the
|
/// The memory allocated to represent the set is released when the
|
||||||
/// factory object that created the set is destroyed.
|
/// factory object that created the set is destroyed.
|
||||||
ImmutableSet Remove(ImmutableSet Old, value_type_ref V) {
|
ImmutableSet Remove(ImmutableSet Old, value_type_ref V) {
|
||||||
return ImmutableSet(F.Remove(Old.Root,V));
|
return ImmutableSet(F.GetCanonicalTree(F.Remove(Old.Root,V)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BumpPtrAllocator& getAllocator() { return F.getAllocator(); }
|
BumpPtrAllocator& getAllocator() { return F.getAllocator(); }
|
||||||
@ -1005,7 +1001,9 @@ public:
|
|||||||
return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
|
return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeTy* getRoot() const { return Root; }
|
TreeTy *getRoot() {
|
||||||
|
return Root;
|
||||||
|
}
|
||||||
|
|
||||||
/// isEmpty - Return true if the set contains no elements.
|
/// isEmpty - Return true if the set contains no elements.
|
||||||
bool isEmpty() const { return !Root; }
|
bool isEmpty() const { return !Root; }
|
||||||
|
Loading…
Reference in New Issue
Block a user