]> granicus.if.org Git - clang/commitdiff
Use the proper post-order traversal in LiveVariables analysis,
authorArtyom Skrobov <Artyom.Skrobov@arm.com>
Thu, 14 Aug 2014 16:04:47 +0000 (16:04 +0000)
committerArtyom Skrobov <Artyom.Skrobov@arm.com>
Thu, 14 Aug 2014 16:04:47 +0000 (16:04 +0000)
to recover the performance after r214064.

Also sorts out the naming for PostOrderCFGView, ReversePostOrderCFGView,
BackwardDataflowWorklist and ForwardDataflowWorklist, to match the accepted
terminology.

Also unifies BackwardDataflowWorklist and ForwardDataflowWorklist to share
the "worklist for prioritization, post-order traversal for fallback" logic,
and to avoid repetitive sorting.

Also cleans up comments in the affected area.

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

include/clang/Analysis/Analyses/DataflowWorklist.h
include/clang/Analysis/Analyses/PostOrderCFGView.h
include/clang/Analysis/Analyses/ThreadSafetyCommon.h
lib/Analysis/Consumed.cpp
lib/Analysis/DataflowWorklist.cpp
lib/Analysis/LiveVariables.cpp
lib/Analysis/PostOrderCFGView.cpp
lib/Analysis/UninitializedValues.cpp

index 11415525a910ea2ca3dc93f1b854a1c0b5820667..c10bb5183e6704ab2afde5c7fb1c60090400ebeb 100644 (file)
@@ -10,7 +10,7 @@
 // DataflowWorklist keeps track of blocks for dataflow analysis. It maintains a
 // vector of blocks for priority processing, and falls back upon a reverse
 // post-order iterator. It supports both forward (used in UninitializedValues)
-// and reverse (used in LiveVariables) analyses.
+// and backward (used in LiveVariables) analyses.
 //
 //===----------------------------------------------------------------------===//
 
 
 namespace clang {
 
-class DataflowWorklistBase {
-protected:
+class DataflowWorklist {
   PostOrderCFGView::iterator PO_I, PO_E;
-  PostOrderCFGView::BlockOrderCompare comparator;
   SmallVector<const CFGBlock *, 20> worklist;
   llvm::BitVector enqueuedBlocks;
 
-  DataflowWorklistBase(const CFG &cfg, PostOrderCFGView &view)
+protected:
+  DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
     : PO_I(view.begin()), PO_E(view.end()),
-      comparator(view.getComparator()),
       enqueuedBlocks(cfg.getNumBlockIDs(), true) {
-        // Treat the first block as already analyzed.
-        if (PO_I != PO_E) {
-          assert(*PO_I == &cfg.getEntry());
+        // For forward analysis, treat the first block as already analyzed.
+        if ((PO_I != PO_E) && (*PO_I == &cfg.getEntry())) {
           enqueuedBlocks[(*PO_I)->getBlockID()] = false;
           ++PO_I;
         }
       }
-};
-
-class DataflowWorklist : DataflowWorklistBase {
 
 public:
-  DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
-    : DataflowWorklistBase(cfg, *Ctx.getAnalysis<PostOrderCFGView>()) {}
-
   void enqueueBlock(const CFGBlock *block);
   void enqueuePredecessors(const CFGBlock *block);
   void enqueueSuccessors(const CFGBlock *block);
   const CFGBlock *dequeue();
+};
 
-  void sortWorklist();
+class BackwardDataflowWorklist : public DataflowWorklist {
+public:
+  BackwardDataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
+    : DataflowWorklist(cfg, *Ctx.getAnalysis<PostOrderCFGView>()) {}
+};
+
+class ForwardDataflowWorklist : public DataflowWorklist {
+public:
+  ForwardDataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
+    : DataflowWorklist(cfg, *Ctx.getAnalysis<ReversePostOrderCFGView>()) {}
 };
 
 } // end clang namespace
index 68e42f225e3dd8cfc3f47a0b8a0e09169af12c2c..7e895cde8a3cd09a61f6ef6a3681411e1c0d3f1f 100644 (file)
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements post order view of the blocks in a CFG.
+// This file implements post order views of the blocks in a CFG.
 //
 //===----------------------------------------------------------------------===//
 
@@ -68,8 +68,7 @@ public:
     }
   };
 
-private:
-  typedef llvm::po_iterator<const CFG*, CFGBlockSet, true>  po_iterator;
+protected:
   std::vector<const CFGBlock*> Blocks;
 
   typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
@@ -107,6 +106,15 @@ public:
   static const void *getTag();
 
   static PostOrderCFGView *create(AnalysisDeclContext &analysisContext);
+
+protected:
+  PostOrderCFGView() {}
+};
+
+class ReversePostOrderCFGView : public PostOrderCFGView {
+public:
+  ReversePostOrderCFGView(const CFG *cfg);
+  static ReversePostOrderCFGView *create(AnalysisDeclContext &analysisContext);
 };
 
 } // end clang namespace
index ef0fd97e4a94e495af6663d9513b89199a90ab77..edd6c8c16866c266a5c34c1ee68b1e91e687867a 100644 (file)
@@ -142,7 +142,7 @@ public:
     if (!dyn_cast_or_null<NamedDecl>(AC.getDecl()))
       return false;
 
-    SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+    SortedGraph = AC.getAnalysis<ReversePostOrderCFGView>();
     if (!SortedGraph)
       return false;
 
index 2b2da2c69a417eda3f83fb1cd9a79faa2965d5fc..47239d098cdd33c686229940fa29630ba51882a3 100644 (file)
@@ -1360,7 +1360,7 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
 
   determineExpectedReturnState(AC, D);
 
-  PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+  PostOrderCFGView *SortedGraph = AC.getAnalysis<ReversePostOrderCFGView>();
   // AC.getCFG()->viewCFG(LangOptions());
   
   BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
index 9b4f4f7d84a0653ec6805c9cd6177c93e6a66071..9cc2a934e630225ba192687c64aba2001a2b8293 100644 (file)
@@ -19,7 +19,7 @@ using namespace clang;
 // but it doesn't control when the algorithm terminates.
 // Initially, enqueuedBlocks is set to true for all blocks;
 // that's not because everything is added initially to the worklist,
-// but instead, to cause the forward analysis to follow the reverse post order
+// but instead, to cause the analysis to follow the initial graph traversal
 // until we enqueue something on the worklist. 
 void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
   if (block && !enqueuedBlocks[block->getBlockID()]) {
@@ -28,10 +28,11 @@ void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
   }
 }
 
-// The forward analysis alternates between essentially two worklists.
+// The analysis alternates between essentially two worklists.
 // A prioritization worklist (SmallVector<const CFGBlock *> worklist)
-// is consulted first, and if it's empty, we consult the reverse
-// post-order traversal (PostOrderCFGView::iterator PO_I).
+// is consulted first, and if it's empty, we consult
+// PostOrderCFGView::iterator PO_I, which implements either post-order traversal
+// for backward analysis, or reverse post-order traversal for forward analysis.
 // The prioritization worklist is used to prioritize analyzing from
 // the beginning, or to prioritize updates fed by back edges.
 // Typically, what gets enqueued on the worklist are back edges, which
@@ -45,22 +46,11 @@ void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
   }
 }
 
-// The reverse analysis uses a simple re-sorting of the worklist to
-// reprioritize it.  It's not as efficient as the two-worklists approach,
-// but it isn't performance sensitive since it's used by the static analyzer,
-// and the static analyzer does far more work that dwarfs the work done here.
-// TODO: It would still be nice to use the same approach for both analyses.
 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();
 }
 
 const CFGBlock *DataflowWorklist::dequeue() {
@@ -71,8 +61,9 @@ const CFGBlock *DataflowWorklist::dequeue() {
   if (!worklist.empty())
     B = worklist.pop_back_val();
 
-  // Next dequeue from the initial reverse post order.  This is the
-  // theoretical ideal in the presence of no back edges.
+  // Next dequeue from the initial graph traversal (either post order or
+  // reverse post order).  This is the theoretical ideal in the presence
+  // of no back edges.
   else if (PO_I != PO_E) {
     B = *PO_I;
     ++PO_I;
@@ -86,7 +77,3 @@ const CFGBlock *DataflowWorklist::dequeue() {
   return B;
 }
 
-void DataflowWorklist::sortWorklist() {
-  std::sort(worklist.begin(), worklist.end(), comparator);
-}
-
index dcde5e7619fe0044cf52259b8a101637f0af44bf..77f7dc386e6aa1772e6ca981e404b119b201c035 100644 (file)
@@ -448,21 +448,18 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
 
   LiveVariablesImpl *LV = new LiveVariablesImpl(AC, killAtAssign);
 
-  // Construct the dataflow worklist.  Enqueue the exit block as the
-  // start of the analysis.
-  DataflowWorklist worklist(*cfg, AC);
+  // Construct the backward dataflow worklist.
+  BackwardDataflowWorklist worklist(*cfg, AC);
   llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
+  llvm::BitVector scannedForAssignments(cfg->getNumBlockIDs());
 
-  // FIXME: we should enqueue using post order.
-  for (CFG::const_iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) {
-    const CFGBlock *block = *it;
-    worklist.enqueueBlock(block);
+  while (const CFGBlock *block = worklist.dequeue()) {
     
     // FIXME: Scan for DeclRefExprs using in the LHS of an assignment.
     // We need to do this because we lack context in the reverse analysis
     // to determine if a DeclRefExpr appears in such a context, and thus
     // doesn't constitute a "use".
-    if (killAtAssign)
+    if (killAtAssign && !scannedForAssignments[block->getBlockID()]) {
       for (CFGBlock::const_iterator bi = block->begin(), be = block->end();
            bi != be; ++bi) {
         if (Optional<CFGStmt> cs = bi->getAs<CFGStmt>()) {
@@ -477,11 +474,9 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
           }
         }
       }
-  }
-  
-  worklist.sortWorklist();
+      scannedForAssignments[block->getBlockID()] = true;
+    }
   
-  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.
     LivenessValues &prevVal = LV->blocksEndToLiveness[block];
index 5a3c8182a140009a1efe2cbdd89b030b3d78d9e4..714292b3f984d441bd4bd0e72e3abc73ca3a5130 100644 (file)
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements post order view of the blocks in a CFG.
+// This file implements post order views of the blocks in a CFG.
 //
 //===----------------------------------------------------------------------===//
 
@@ -17,14 +17,16 @@ using namespace clang;
 
 void PostOrderCFGView::anchor() { }
 
-PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
+ReversePostOrderCFGView::ReversePostOrderCFGView(const CFG *cfg) {
   Blocks.reserve(cfg->getNumBlockIDs());
   CFGBlockSet BSet(cfg);
-    
+
+  typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
+
   for (po_iterator I = po_iterator::begin(cfg, BSet),
                    E = po_iterator::end(cfg, BSet); I != E; ++I) {
-    BlockOrder[*I] = Blocks.size() + 1;
     Blocks.push_back(*I);      
+    BlockOrder[*I] = Blocks.size();
   }
 }
 
@@ -47,3 +49,49 @@ bool PostOrderCFGView::BlockOrderCompare::operator()(const CFGBlock *b1,
   return b1V > b2V;
 }
 
+PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
+  unsigned size = cfg->getNumBlockIDs();
+  Blocks.reserve(size);
+  CFGBlockSet BSet(cfg);
+
+  typedef llvm::po_iterator<const CFG*, CFGBlockSet, true,
+                            llvm::GraphTraits<llvm::Inverse<const CFG*> >
+                           > po_iterator;
+
+  for (po_iterator I = po_iterator::begin(cfg, BSet),
+                   E = po_iterator::end(cfg, BSet); I != E; ++I) {
+    Blocks.push_back(*I);      
+    BlockOrder[*I] = Blocks.size();
+  }
+
+  // It may be that some blocks are inaccessible going from the CFG exit upwards
+  // (e.g. infinite loops); we still need to add them.
+  for (CFG::const_iterator I = cfg->begin(), E = cfg->end();
+       (Blocks.size() < size) && (I != E); ++I) {
+    const CFGBlock* block = *I;
+    // Add a chain going upwards.
+    while (!BlockOrder.count(block)) {
+      Blocks.push_back(block);
+      BlockOrder[block] = Blocks.size();
+      CFGBlock::const_pred_iterator PI = block->pred_begin(),
+                                    PE = block->pred_end();
+      for (; PI != PE; ++PI) {
+        const CFGBlock* pred = *PI;
+        if (pred && !BlockOrder.count(pred)) {
+          block = pred;
+          break;
+        }
+      }
+      // Chain ends when we couldn't find an unmapped pred.
+      if (PI == PE) break;
+    }
+  }
+}
+
+ReversePostOrderCFGView *
+ReversePostOrderCFGView::create(AnalysisDeclContext &ctx) {
+  const CFG *cfg = ctx.getCFG();
+  if (!cfg)
+    return nullptr;
+  return new ReversePostOrderCFGView(cfg);
+}
index b6702b0609c5ff5950777cdcec57f8c9cc6a82c7..0f93fe8981c2a2af8c8accfa5c52358337391705 100644 (file)
@@ -771,7 +771,7 @@ void clang::runUninitializedVariablesAnalysis(
   }
 
   // Proceed with the workist.
-  DataflowWorklist worklist(cfg, ac);
+  ForwardDataflowWorklist worklist(cfg, ac);
   llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
   worklist.enqueueSuccessors(&cfg.getEntry());
   llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);