]> granicus.if.org Git - clang/commitdiff
[analyzer] Remove superquadratic behaviour from DataflowWorklist
authorAlexander Shaposhnikov <shal1t712@gmail.com>
Thu, 13 Oct 2016 21:31:46 +0000 (21:31 +0000)
committerAlexander Shaposhnikov <shal1t712@gmail.com>
Thu, 13 Oct 2016 21:31:46 +0000 (21:31 +0000)
The class DataflowWorklist internally maintains a sorted list of pointers to CFGBlock
and the method enqueuePredecessors has to call sortWorklist to maintain the invariant.
The implementation based on vector + sort works well for small sizes
but gets infeasible for relatively large sizes. In particular the issue takes place
for some cryptographic libraries which use code generation.
The diff replaces vector + sort with priority queue.
For one of the implementations of AES this patch reduces
the time for analysis from 204 seconds to 8 seconds.

Test plan: make -j8 check-clang

Differential revision: https://reviews.llvm.org/D25503

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

lib/Analysis/LiveVariables.cpp

index 5e0a9a0d73c8f4f710cdf1c581f279c25c3a7ab2..cd73a62e6918c1af735ec954bcca89f0df96c3e4 100644 (file)
@@ -19,6 +19,7 @@
 #include "clang/Analysis/CFG.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/PriorityQueue.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <vector>
@@ -28,20 +29,21 @@ using namespace clang;
 namespace {
 
 class DataflowWorklist {
-  SmallVector<const CFGBlock *, 20> worklist;
   llvm::BitVector enqueuedBlocks;
   PostOrderCFGView *POV;
+  llvm::PriorityQueue<const CFGBlock *, SmallVector<const CFGBlock *, 20>,
+                      PostOrderCFGView::BlockOrderCompare> worklist;
+
 public:
   DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
     : enqueuedBlocks(cfg.getNumBlockIDs()),
-      POV(Ctx.getAnalysis<PostOrderCFGView>()) {}
+      POV(Ctx.getAnalysis<PostOrderCFGView>()),
+      worklist(POV->getComparator()) {}
   
   void enqueueBlock(const CFGBlock *block);
   void enqueuePredecessors(const CFGBlock *block);
 
   const CFGBlock *dequeue();
-
-  void sortWorklist();
 };
 
 }
@@ -49,31 +51,22 @@ public:
 void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
   if (block && !enqueuedBlocks[block->getBlockID()]) {
     enqueuedBlocks[block->getBlockID()] = true;
-    worklist.push_back(block);
+    worklist.push(block);
   }
 }
 
 void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
-  const unsigned OldWorklistSize = worklist.size();
   for (CFGBlock::const_pred_iterator I = block->pred_begin(),
        E = block->pred_end(); I != E; ++I) {
     enqueueBlock(*I);
   }
-  
-  if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
-    return;
-
-  sortWorklist();
-}
-
-void DataflowWorklist::sortWorklist() {
-  std::sort(worklist.begin(), worklist.end(), POV->getComparator());
 }
 
 const CFGBlock *DataflowWorklist::dequeue() {
   if (worklist.empty())
     return nullptr;
-  const CFGBlock *b = worklist.pop_back_val();
+  const CFGBlock *b = worklist.top();
+  worklist.pop();
   enqueuedBlocks[b->getBlockID()] = false;
   return b;
 }
@@ -528,8 +521,6 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
       }
   }
   
-  worklist.sortWorklist();
-  
   while (const CFGBlock *block = worklist.dequeue()) {
     // Determine if the block's end value has changed.  If not, we
     // have nothing left to do for this block.