llvm.org GIT mirror llvm / 8b8a7fc
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80955 91177308-0d34-0410-b5e6-96231b3b80d8 Ted Kremenek 11 years ago
2 changed file(s) with 62 addition(s) and 63 deletion(s). Raw diff Collapse all Expand all
8989 ImmutableMap GetEmptyMap() { return ImmutableMap(F.GetEmptyTree()); }
9090
9191 ImmutableMap Add(ImmutableMap Old, key_type_ref K, data_type_ref D) {
92 return ImmutableMap(F.Add(Old.Root,
93 std::make_pair(K,D)));
92 TreeTy *T = F.Add(Old.Root, std::make_pair(K,D));
93 return ImmutableMap(F.GetCanonicalTree(T));
9494 }
9595
9696 ImmutableMap Remove(ImmutableMap Old, key_type_ref K) {
97 return ImmutableMap(F.Remove(Old.Root,K));
97 TreeTy *T = F.Remove(Old.Root,K);
98 return ImmutableMap(F.GetCanonicalTree(T));
9899 }
99100
100101 private:
430430 // returned to the caller.
431431 //===--------------------------------------------------===//
432432
433 TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) {
434 // Search the FoldingSet bucket for a Tree with the same digest.
435 FoldingSetNodeID ID;
436 unsigned digest = TreeTy::ComputeDigest(L, R, V);
437 ID.AddInteger(digest);
438 unsigned hash = ID.ComputeHash();
439
440 typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash);
441 typename CacheTy::bucket_iterator E = Cache.bucket_end(hash);
442
443 for (; I != E; ++I) {
444 TreeTy* T = &*I;
445
446 if (T->ComputeDigest() != digest)
447 continue;
448
449 // We found a collision. Perform a comparison of Contents('T')
450 // with Contents('L')+'V'+Contents('R').
451 typename TreeTy::iterator TI = T->begin(), TE = T->end();
452
453 // First compare Contents('L') with the (initial) contents of T.
454 if (!CompareTreeWithSection(L, TI, TE))
455 continue;
456
457 // Now compare the new data element.
458 if (TI == TE || !TI->ElementEqual(V))
459 continue;
460
461 ++TI;
462
463 // Now compare the remainder of 'T' with 'R'.
464 if (!CompareTreeWithSection(R, TI, TE))
465 continue;
466
467 if (TI != TE)
468 continue; // Contents('R') did not match suffix of 'T'.
469
470 // Trees did match! Return 'T'.
471 return T;
472 }
473
474 // No tree with the contents: Contents('L')+'V'+Contents('R').
475 // Create it. Allocate the new tree node and insert it into the cache.
433 TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) {
476434 BumpPtrAllocator& A = getAllocator();
477435 TreeTy* T = (TreeTy*) A.Allocate();
478436 new (T) TreeTy(L,R,V,IncrementHeight(L,R));
479
480 // We do not insert 'T' into the FoldingSet here. This is because
481 // this tree is still mutable and things may get rebalanced.
482 // Because our digest is associative and based on the contents of
483 // the set, this should hopefully not cause any strange bugs.
484 // 'T' is inserted by 'MarkImmutable'.
485437 return T;
486438 }
487439
614566 T->MarkImmutable();
615567 MarkImmutable(Left(T));
616568 MarkImmutable(Right(T));
617
618 // Now that the node is immutable it can safely be inserted
619 // into the node cache.
620 llvm::FoldingSetNodeID ID;
621 ID.AddInteger(T->ComputeDigest());
622 Cache.InsertNode(T, (void*) &*Cache.bucket_end(ID.ComputeHash()));
569 }
570
571 public:
572 TreeTy *GetCanonicalTree(TreeTy *TNew) {
573 if (!TNew)
574 return NULL;
575
576 // Search the FoldingSet bucket for a Tree with the same digest.
577 FoldingSetNodeID ID;
578 unsigned digest = TNew->ComputeDigest();
579 ID.AddInteger(digest);
580 unsigned hash = ID.ComputeHash();
581
582 typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash);
583 typename CacheTy::bucket_iterator E = Cache.bucket_end(hash);
584
585 for (; I != E; ++I) {
586 TreeTy *T = &*I;
587
588 if (T->ComputeDigest() != digest)
589 continue;
590
591 // We found a collision. Perform a comparison of Contents('T')
592 // with Contents('L')+'V'+Contents('R').
593 typename TreeTy::iterator TI = T->begin(), TE = T->end();
594
595 // First compare Contents('L') with the (initial) contents of T.
596 if (!CompareTreeWithSection(TNew->getLeft(), TI, TE))
597 continue;
598
599 // Now compare the new data element.
600 if (TI == TE || !TI->ElementEqual(TNew->getValue()))
601 continue;
602
603 ++TI;
604
605 // Now compare the remainder of 'T' with 'R'.
606 if (!CompareTreeWithSection(TNew->getRight(), TI, TE))
607 continue;
608
609 if (TI != TE)
610 continue; // Contents('R') did not match suffix of 'T'.
611
612 // Trees did match! Return 'T'.
613 return T;
614 }
615
616 // 'TNew' is the only tree of its kind. Return it.
617 Cache.InsertNode(TNew, (void*) &*Cache.bucket_end(hash));
618 return TNew;
623619 }
624620 };
625621
939935 typedef ImutAVLTree TreeTy;
940936
941937 private:
942 TreeTy* Root;
943
938 TreeTy *Root;
939
944940 public:
945941 /// Constructs a set from a pointer to a tree root. In general one
946942 /// should use a Factory object to create sets instead of directly
968964 /// The memory allocated to represent the set is released when the
969965 /// factory object that created the set is destroyed.
970966 ImmutableSet Add(ImmutableSet Old, value_type_ref V) {
971 return ImmutableSet(F.Add(Old.Root,V));
967 return ImmutableSet(F.GetCanonicalTree(F.Add(Old.Root,V)));
972968 }
973969
974970 /// Remove - Creates a new immutable set that contains all of the values
979975 /// The memory allocated to represent the set is released when the
980976 /// factory object that created the set is destroyed.
981977 ImmutableSet Remove(ImmutableSet Old, value_type_ref V) {
982 return ImmutableSet(F.Remove(Old.Root,V));
978 return ImmutableSet(F.GetCanonicalTree(F.Remove(Old.Root,V)));
983979 }
984980
985981 BumpPtrAllocator& getAllocator() { return F.getAllocator(); }
10041000 return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root;
10051001 }
10061002
1007 TreeTy* getRoot() const { return Root; }
1003 TreeTy *getRoot() {
1004 return Root;
1005 }
10081006
10091007 /// isEmpty - Return true if the set contains no elements.
10101008 bool isEmpty() const { return !Root; }