[cfe-commits] r139968 - /cfe/trunk/lib/Analysis/LiveVariables.cpp
Ted Kremenek
kremenek at apple.com
Fri Sep 16 16:01:39 PDT 2011
Author: kremenek
Date: Fri Sep 16 18:01:39 2011
New Revision: 139968
URL: http://llvm.org/viewvc/llvm-project?rev=139968&view=rev
Log:
Fix massive LiveVariables regression (due to LiveVariables rewrite) by addressing two performance problems:
- Speed of "merge()", which merged data flow facts. This was doing a set canonicalization on every insertion, which was super slow.
To fix this, we use ImmutableSetRef.
- Visit CFGBlocks in reverse postorder. This is a huge speedup, as on some test cases the algorithm would take many iterations
to converge.
This contains a bunch of copy-paste from UninitializedValues.cpp and ThreadSafety.cpp. The idea
was to get something working first, and then refactor the common logic for all three files into
a separate analysis/library entry point.
Modified:
cfe/trunk/lib/Analysis/LiveVariables.cpp
Modified: cfe/trunk/lib/Analysis/LiveVariables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/LiveVariables.cpp?rev=139968&r1=139967&r2=139968&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/LiveVariables.cpp (original)
+++ cfe/trunk/lib/Analysis/LiveVariables.cpp Fri Sep 16 18:01:39 2011
@@ -4,6 +4,9 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/DenseMap.h"
+
#include <deque>
#include <algorithm>
#include <vector>
@@ -11,31 +14,199 @@
using namespace clang;
namespace {
- class LiveVariablesImpl {
- public:
- AnalysisContext &analysisContext;
- std::vector<LiveVariables::LivenessValues> cfgBlockValues;
- llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
- llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
- llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
- llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
- llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
- llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment;
- const bool killAtAssign;
-
- LiveVariables::LivenessValues
- merge(LiveVariables::LivenessValues valsA,
- LiveVariables::LivenessValues valsB);
-
- LiveVariables::LivenessValues runOnBlock(const CFGBlock *block,
- LiveVariables::LivenessValues val,
- LiveVariables::Observer *obs = 0);
- void dumpBlockLiveness(const SourceManager& M);
+// FIXME: This is copy-pasted from ThreadSafety.c. I wanted a patch that
+// contained working code before refactoring the implementation of both
+// files.
+class CFGBlockSet {
+ llvm::BitVector VisitedBlockIDs;
+
+public:
+ // po_iterator requires this iterator, but the only interface needed is the
+ // value_type typedef.
+ struct iterator {
+ typedef const CFGBlock *value_type;
+ };
+
+ CFGBlockSet() {}
+ CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
+
+ /// \brief Set the bit associated with a particular CFGBlock.
+ /// This is the important method for the SetType template parameter.
+ bool insert(const CFGBlock *Block) {
+ // Note that insert() is called by po_iterator, which doesn't check to make
+ // sure that Block is non-null. Moreover, the CFGBlock iterator will
+ // occasionally hand out null pointers for pruned edges, so we catch those
+ // here.
+ if (Block == 0)
+ return false; // if an edge is trivially false.
+ if (VisitedBlockIDs.test(Block->getBlockID()))
+ return false;
+ VisitedBlockIDs.set(Block->getBlockID());
+ return true;
+ }
+
+ /// \brief Check if the bit for a CFGBlock has been already set.
+ /// This method is for tracking visited blocks in the main threadsafety loop.
+ /// Block must not be null.
+ bool alreadySet(const CFGBlock *Block) {
+ return VisitedBlockIDs.test(Block->getBlockID());
+ }
+};
- LiveVariablesImpl(AnalysisContext &ac, bool KillAtAssign)
- : analysisContext(ac), killAtAssign(KillAtAssign) {}
+/// \brief We create a helper class which we use to iterate through CFGBlocks in
+/// the topological order.
+class TopologicallySortedCFG {
+ typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator;
+
+ std::vector<const CFGBlock*> Blocks;
+
+ typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy;
+ BlockOrderTy BlockOrder;
+
+
+public:
+ typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
+
+ TopologicallySortedCFG(const CFG *CFGraph) {
+ Blocks.reserve(CFGraph->getNumBlockIDs());
+ CFGBlockSet BSet(CFGraph);
+
+ for (po_iterator I = po_iterator::begin(CFGraph, BSet),
+ E = po_iterator::end(CFGraph, BSet); I != E; ++I) {
+ BlockOrder[*I] = Blocks.size() + 1;
+ Blocks.push_back(*I);
+ }
+ }
+
+ iterator begin() {
+ return Blocks.rbegin();
+ }
+
+ iterator end() {
+ return Blocks.rend();
+ }
+
+ bool empty() {
+ return begin() == end();
+ }
+
+ struct BlockOrderCompare;
+ friend struct BlockOrderCompare;
+
+ struct BlockOrderCompare {
+ const TopologicallySortedCFG &TSC;
+ public:
+ BlockOrderCompare(const TopologicallySortedCFG &tsc) : TSC(tsc) {}
+
+ bool operator()(const CFGBlock *b1, const CFGBlock *b2) const {
+ TopologicallySortedCFG::BlockOrderTy::const_iterator b1It = TSC.BlockOrder.find(b1);
+ TopologicallySortedCFG::BlockOrderTy::const_iterator b2It = TSC.BlockOrder.find(b2);
+
+ unsigned b1V = (b1It == TSC.BlockOrder.end()) ? 0 : b1It->second;
+ unsigned b2V = (b2It == TSC.BlockOrder.end()) ? 0 : b2It->second;
+ return b1V > b2V;
+ }
};
+
+ BlockOrderCompare getComparator() const {
+ return BlockOrderCompare(*this);
+ }
+};
+
+class DataflowWorklist {
+ SmallVector<const CFGBlock *, 20> worklist;
+ llvm::BitVector enqueuedBlocks;
+ TopologicallySortedCFG TSC;
+public:
+ DataflowWorklist(const CFG &cfg)
+ : enqueuedBlocks(cfg.getNumBlockIDs()),
+ TSC(&cfg) {}
+
+ void enqueueBlock(const CFGBlock *block);
+ void enqueueSuccessors(const CFGBlock *block);
+ void enqueuePredecessors(const CFGBlock *block);
+
+ const CFGBlock *dequeue();
+
+ void sortWorklist();
+};
+
+}
+
+void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
+ if (block && !enqueuedBlocks[block->getBlockID()]) {
+ enqueuedBlocks[block->getBlockID()] = true;
+ worklist.push_back(block);
+ }
+}
+
+void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
+ const unsigned OldWorklistSize = worklist.size();
+ for (CFGBlock::const_succ_iterator I = block->succ_begin(),
+ E = block->succ_end(); I != E; ++I) {
+ enqueueBlock(*I);
+ }
+
+ if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
+ return;
+
+ sortWorklist();
+}
+
+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(), TSC.getComparator());
+}
+
+
+const CFGBlock *DataflowWorklist::dequeue() {
+ if (worklist.empty())
+ return 0;
+ const CFGBlock *b = worklist.back();
+ worklist.pop_back();
+ enqueuedBlocks[b->getBlockID()] = false;
+ return b;
+}
+
+namespace {
+class LiveVariablesImpl {
+public:
+ AnalysisContext &analysisContext;
+ std::vector<LiveVariables::LivenessValues> cfgBlockValues;
+ llvm::ImmutableSet<const Stmt *>::Factory SSetFact;
+ llvm::ImmutableSet<const VarDecl *>::Factory DSetFact;
+ llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness;
+ llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksBeginToLiveness;
+ llvm::DenseMap<const Stmt *, LiveVariables::LivenessValues> stmtsToLiveness;
+ llvm::DenseMap<const DeclRefExpr *, unsigned> inAssignment;
+ const bool killAtAssign;
+
+ LiveVariables::LivenessValues
+ merge(LiveVariables::LivenessValues valsA,
+ LiveVariables::LivenessValues valsB);
+
+ LiveVariables::LivenessValues runOnBlock(const CFGBlock *block,
+ LiveVariables::LivenessValues val,
+ LiveVariables::Observer *obs = 0);
+
+ void dumpBlockLiveness(const SourceManager& M);
+
+ LiveVariablesImpl(AnalysisContext &ac, bool KillAtAssign)
+ : analysisContext(ac), killAtAssign(KillAtAssign) {}
+};
}
static LiveVariablesImpl &getImpl(void *x) {
@@ -56,9 +227,12 @@
namespace {
template <typename SET>
- SET mergeSets(typename SET::Factory &F, SET A, SET B) {
+ SET mergeSets(SET A, SET B) {
+ if (A.isEmpty())
+ return B;
+
for (typename SET::iterator it = B.begin(), ei = B.end(); it != ei; ++it) {
- A = F.add(A, *it);
+ A = A.add(*it);
}
return A;
}
@@ -67,8 +241,22 @@
LiveVariables::LivenessValues
LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
LiveVariables::LivenessValues valsB) {
- return LiveVariables::LivenessValues(mergeSets(SSetFact, valsA.liveStmts, valsB.liveStmts),
- mergeSets(DSetFact, valsA.liveDecls, valsB.liveDecls));
+
+ llvm::ImmutableSetRef<const Stmt *>
+ SSetRefA(valsA.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory()),
+ SSetRefB(valsB.liveStmts.getRootWithoutRetain(), SSetFact.getTreeFactory());
+
+
+ llvm::ImmutableSetRef<const VarDecl *>
+ DSetRefA(valsA.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory()),
+ DSetRefB(valsB.liveDecls.getRootWithoutRetain(), DSetFact.getTreeFactory());
+
+
+ SSetRefA = mergeSets(SSetRefA, SSetRefB);
+ DSetRefA = mergeSets(DSetRefA, DSetRefB);
+
+ return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(),
+ DSetRefA.asImmutableSet());
}
bool LiveVariables::LivenessValues::equals(const LivenessValues &V) const {
@@ -100,29 +288,6 @@
//===----------------------------------------------------------------------===//
namespace {
-class Worklist {
- llvm::BitVector isBlockEnqueued;
- std::deque<const CFGBlock *> workListContents;
-public:
- Worklist(CFG &cfg) : isBlockEnqueued(cfg.getNumBlockIDs()) {}
-
- bool empty() const { return workListContents.empty(); }
-
- const CFGBlock *getNextItem() {
- const CFGBlock *block = workListContents.front();
- workListContents.pop_front();
- isBlockEnqueued[block->getBlockID()] = false;
- return block;
- }
-
- void enqueueBlock(const CFGBlock *block) {
- if (!isBlockEnqueued[block->getBlockID()]) {
- isBlockEnqueued[block->getBlockID()] = true;
- workListContents.push_back(block);
- }
- }
-};
-
class TransferFunctions : public StmtVisitor<TransferFunctions> {
LiveVariablesImpl &LV;
LiveVariables::LivenessValues &val;
@@ -390,7 +555,7 @@
// Construct the dataflow worklist. Enqueue the exit block as the
// start of the analysis.
- Worklist worklist(*cfg);
+ DataflowWorklist worklist(*cfg);
llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
// FIXME: we should enqueue using post order.
@@ -418,10 +583,9 @@
}
}
- while (!worklist.empty()) {
- // Dequeue blocks in FIFO order.
- const CFGBlock *block = worklist.getNextItem();
-
+ 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.
LivenessValues &prevVal = LV->blocksEndToLiveness[block];
@@ -430,8 +594,9 @@
LivenessValues val;
for (CFGBlock::const_succ_iterator it = block->succ_begin(),
ei = block->succ_end(); it != ei; ++it) {
- if (const CFGBlock *succ = *it)
+ if (const CFGBlock *succ = *it) {
val = LV->merge(val, LV->blocksBeginToLiveness[succ]);
+ }
}
if (!everAnalyzedBlock[block->getBlockID()])
@@ -445,12 +610,7 @@
LV->blocksBeginToLiveness[block] = LV->runOnBlock(block, val);
// Enqueue the value to the predecessors.
- for (CFGBlock::const_pred_iterator it = block->pred_begin(),
- ei = block->pred_end(); it != ei; ++it)
- {
- if (const CFGBlock *pred = *it)
- worklist.enqueueBlock(pred);
- }
+ worklist.enqueuePredecessors(block);
}
return new LiveVariables(LV);
More information about the cfe-commits
mailing list