]> granicus.if.org Git - clang/commitdiff
[analyzer] Fix inefficiency in dead symbol removal
authorPavel Labath <labath@google.com>
Mon, 19 Aug 2013 15:23:34 +0000 (15:23 +0000)
committerPavel Labath <labath@google.com>
Mon, 19 Aug 2013 15:23:34 +0000 (15:23 +0000)
Summary:
ScanReachableSymbols uses a "visited" set to avoid scanning the same object
twice. However, it did not use the optimization for LazyCompoundVal objects,
which resulted in exponential complexity for long chains of temporary objects.
Adding this resulted in a decrease of analysis time from >3h to 3 seconds for
some files.

Reviewers: jordan_rose

CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1398

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188677 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
lib/StaticAnalyzer/Core/ProgramState.cpp

index ed1ab8c4cb45440380c48bd36077afec2c35b752..96f62423393da6b6626788a6ae7b1cebcce09338 100644 (file)
@@ -798,7 +798,7 @@ CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
 /// A Utility class that allows to visit the reachable symbols using a custom
 /// SymbolVisitor.
 class ScanReachableSymbols {
-  typedef llvm::DenseMap<const void*, unsigned> VisitedItems;
+  typedef llvm::DenseSet<const void*> VisitedItems;
 
   VisitedItems visited;
   ProgramStateRef state;
@@ -808,6 +808,7 @@ public:
   ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v)
     : state(st), visitor(v) {}
 
+  bool scan(nonloc::LazyCompoundVal val);
   bool scan(nonloc::CompoundVal val);
   bool scan(SVal val);
   bool scan(const MemRegion *R);
index 653b69bf4860164bc19be267e6adbd6678829c03..fbd3fc526d3bb5c9f4263afc6e8b689c0e4ba443 100644 (file)
@@ -526,6 +526,19 @@ ProgramStateRef ProgramStateManager::removeGDM(ProgramStateRef state, void *Key)
   return getPersistentState(NewState);
 }
 
+bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) {
+  bool wasVisited = !visited.insert(val.getCVData()).second;
+  if (wasVisited)
+    return true;
+
+  StoreManager &StoreMgr = state->getStateManager().getStoreManager();
+  // FIXME: We don't really want to use getBaseRegion() here because pointer
+  // arithmetic doesn't apply, but scanReachableSymbols only accepts base
+  // regions right now.
+  const MemRegion *R = val.getRegion()->getBaseRegion();
+  return StoreMgr.scanReachableSymbols(val.getStore(), R, *this);
+}
+
 bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
   for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I)
     if (!scan(*I))
@@ -535,10 +548,9 @@ bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
 }
 
 bool ScanReachableSymbols::scan(const SymExpr *sym) {
-  unsigned &isVisited = visited[sym];
-  if (isVisited)
+  bool wasVisited = !visited.insert(sym).second;
+  if (wasVisited)
     return true;
-  isVisited = 1;
   
   if (!visitor.VisitSymbol(sym))
     return false;
@@ -570,16 +582,8 @@ bool ScanReachableSymbols::scan(SVal val) {
     return scan(X->getRegion());
 
   if (Optional<nonloc::LazyCompoundVal> X =
-          val.getAs<nonloc::LazyCompoundVal>()) {
-    StoreManager &StoreMgr = state->getStateManager().getStoreManager();
-    // FIXME: We don't really want to use getBaseRegion() here because pointer
-    // arithmetic doesn't apply, but scanReachableSymbols only accepts base
-    // regions right now.
-    if (!StoreMgr.scanReachableSymbols(X->getStore(),
-                                       X->getRegion()->getBaseRegion(),
-                                       *this))
-      return false;
-  }
+          val.getAs<nonloc::LazyCompoundVal>())
+    return scan(*X);
 
   if (Optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
     return scan(X->getLoc());
@@ -600,11 +604,9 @@ bool ScanReachableSymbols::scan(const MemRegion *R) {
   if (isa<MemSpaceRegion>(R))
     return true;
   
-  unsigned &isVisited = visited[R];
-  if (isVisited)
+  bool wasVisited = !visited.insert(R).second;
+  if (wasVisited)
     return true;
-  isVisited = 1;
-  
   
   if (!visitor.VisitMemRegion(R))
     return false;