mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 00:06:50 +00:00
[analyzer] Remove superquadratic behaviour from DataflowWorklist
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 llvm-svn: 284166
This commit is contained in:
parent
3baae885e1
commit
fd905fcc14
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user