Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 5b4b6e9

Browse files
Artyom SkrobovArtyom Skrobov
Artyom Skrobov
authored and
Artyom Skrobov
committed
Factoring DataflowWorklist out of LiveVariables and UninitializedValues analyses
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@214064 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 0a07c05 commit 5b4b6e9

File tree

5 files changed

+149
-117
lines changed

5 files changed

+149
-117
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===- DataflowWorklist.h - worklist for dataflow analysis --------*- C++ --*-//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// DataflowWorklist is used in LiveVariables and UninitializedValues analyses
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_DATAFLOW_WORKLIST
15+
#define LLVM_CLANG_DATAFLOW_WORKLIST
16+
17+
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
18+
19+
namespace clang {
20+
21+
class DataflowWorklist {
22+
PostOrderCFGView::iterator PO_I, PO_E;
23+
PostOrderCFGView::BlockOrderCompare comparator;
24+
SmallVector<const CFGBlock *, 20> worklist;
25+
llvm::BitVector enqueuedBlocks;
26+
27+
DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
28+
: PO_I(view.begin()), PO_E(view.end()),
29+
comparator(view.getComparator()),
30+
enqueuedBlocks(cfg.getNumBlockIDs(), true) {
31+
// Treat the first block as already analyzed.
32+
if (PO_I != PO_E) {
33+
assert(*PO_I == &cfg.getEntry());
34+
enqueuedBlocks[(*PO_I)->getBlockID()] = false;
35+
++PO_I;
36+
}
37+
}
38+
39+
public:
40+
DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
41+
: DataflowWorklist(cfg, *Ctx.getAnalysis<PostOrderCFGView>()) {}
42+
43+
void enqueueBlock(const CFGBlock *block);
44+
void enqueuePredecessors(const CFGBlock *block);
45+
void enqueueSuccessors(const CFGBlock *block);
46+
const CFGBlock *dequeue();
47+
48+
void sortWorklist();
49+
};
50+
51+
} // end clang namespace
52+
53+
#endif

lib/Analysis/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ add_clang_library(clangAnalysis
1212
CocoaConventions.cpp
1313
Consumed.cpp
1414
Dominators.cpp
15+
DataflowWorklist.cpp
1516
FormatString.cpp
1617
LiveVariables.cpp
1718
ObjCNoReturn.cpp

lib/Analysis/DataflowWorklist.cpp

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//===- DataflowWorklist.cpp - worklist for dataflow analysis ------*- C++ --*-//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// DataflowWorklist is used in LiveVariables and UninitializedValues analyses
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "clang/Analysis/Analyses/DataflowWorklist.h"
15+
16+
using namespace clang;
17+
18+
// Marking a block as enqueued means that it cannot be re-added to the worklist,
19+
// but it doesn't control when the algorithm terminates.
20+
// Initially, enqueuedBlocks is set to true for all blocks;
21+
// that's not because everything is added initially to the worklist,
22+
// but instead, to cause the forward analysis to follow the reverse post order
23+
// until we enqueue something on the worklist.
24+
void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
25+
if (block && !enqueuedBlocks[block->getBlockID()]) {
26+
enqueuedBlocks[block->getBlockID()] = true;
27+
worklist.push_back(block);
28+
}
29+
}
30+
31+
// The forward analysis alternates between essentially two worklists.
32+
// A prioritization worklist (SmallVector<const CFGBlock *> worklist)
33+
// is consulted first, and if it's empty, we consult the reverse
34+
// post-order traversal (PostOrderCFGView::iterator PO_I).
35+
// The prioritization worklist is used to prioritize analyzing from
36+
// the beginning, or to prioritize updates fed by back edges.
37+
// Typically, what gets enqueued on the worklist are back edges, which
38+
// we want to prioritize analyzing first, because that causes dataflow facts
39+
// to flow up the graph, which we then want to propagate forward.
40+
// In practice this can cause the analysis to converge much faster.
41+
void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
42+
for (CFGBlock::const_succ_iterator I = block->succ_begin(),
43+
E = block->succ_end(); I != E; ++I) {
44+
enqueueBlock(*I);
45+
}
46+
}
47+
48+
// The reverse analysis uses a simple re-sorting of the worklist to
49+
// reprioritize it. It's not as efficient as the two-worklists approach,
50+
// but it isn't performance sensitive since it's used by the static analyzer,
51+
// and the static analyzer does far more work that dwarfs the work done here.
52+
// TODO: It would still be nice to use the same approach for both analyses.
53+
void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
54+
const unsigned OldWorklistSize = worklist.size();
55+
for (CFGBlock::const_pred_iterator I = block->pred_begin(),
56+
E = block->pred_end(); I != E; ++I) {
57+
enqueueBlock(*I);
58+
}
59+
60+
if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
61+
return;
62+
63+
sortWorklist();
64+
}
65+
66+
const CFGBlock *DataflowWorklist::dequeue() {
67+
const CFGBlock *B = nullptr;
68+
69+
// First dequeue from the worklist. This can represent
70+
// updates along backedges that we want propagated as quickly as possible.
71+
if (!worklist.empty())
72+
B = worklist.pop_back_val();
73+
74+
// Next dequeue from the initial reverse post order. This is the
75+
// theoretical ideal in the presence of no back edges.
76+
else if (PO_I != PO_E) {
77+
B = *PO_I;
78+
++PO_I;
79+
}
80+
else {
81+
return nullptr;
82+
}
83+
84+
assert(enqueuedBlocks[B->getBlockID()] == true);
85+
enqueuedBlocks[B->getBlockID()] = false;
86+
return B;
87+
}
88+
89+
void DataflowWorklist::sortWorklist() {
90+
std::sort(worklist.begin(), worklist.end(), comparator);
91+
}
92+

lib/Analysis/LiveVariables.cpp

+1-55
Original file line numberDiff line numberDiff line change
@@ -14,70 +14,16 @@
1414
#include "clang/Analysis/Analyses/LiveVariables.h"
1515
#include "clang/AST/Stmt.h"
1616
#include "clang/AST/StmtVisitor.h"
17-
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
17+
#include "clang/Analysis/Analyses/DataflowWorklist.h"
1818
#include "clang/Analysis/AnalysisContext.h"
1919
#include "clang/Analysis/CFG.h"
2020
#include "llvm/ADT/DenseMap.h"
21-
#include "llvm/ADT/PostOrderIterator.h"
2221
#include "llvm/Support/raw_ostream.h"
2322
#include <algorithm>
2423
#include <vector>
2524

2625
using namespace clang;
2726

28-
namespace {
29-
30-
class DataflowWorklist {
31-
SmallVector<const CFGBlock *, 20> worklist;
32-
llvm::BitVector enqueuedBlocks;
33-
PostOrderCFGView *POV;
34-
public:
35-
DataflowWorklist(const CFG &cfg, AnalysisDeclContext &Ctx)
36-
: enqueuedBlocks(cfg.getNumBlockIDs()),
37-
POV(Ctx.getAnalysis<PostOrderCFGView>()) {}
38-
39-
void enqueueBlock(const CFGBlock *block);
40-
void enqueuePredecessors(const CFGBlock *block);
41-
42-
const CFGBlock *dequeue();
43-
44-
void sortWorklist();
45-
};
46-
47-
}
48-
49-
void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
50-
if (block && !enqueuedBlocks[block->getBlockID()]) {
51-
enqueuedBlocks[block->getBlockID()] = true;
52-
worklist.push_back(block);
53-
}
54-
}
55-
56-
void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
57-
const unsigned OldWorklistSize = worklist.size();
58-
for (CFGBlock::const_pred_iterator I = block->pred_begin(),
59-
E = block->pred_end(); I != E; ++I) {
60-
enqueueBlock(*I);
61-
}
62-
63-
if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
64-
return;
65-
66-
sortWorklist();
67-
}
68-
69-
void DataflowWorklist::sortWorklist() {
70-
std::sort(worklist.begin(), worklist.end(), POV->getComparator());
71-
}
72-
73-
const CFGBlock *DataflowWorklist::dequeue() {
74-
if (worklist.empty())
75-
return nullptr;
76-
const CFGBlock *b = worklist.pop_back_val();
77-
enqueuedBlocks[b->getBlockID()] = false;
78-
return b;
79-
}
80-
8127
namespace {
8228
class LiveVariablesImpl {
8329
public:

lib/Analysis/UninitializedValues.cpp

+2-62
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "clang/AST/Attr.h"
1616
#include "clang/AST/Decl.h"
1717
#include "clang/AST/StmtVisitor.h"
18-
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
18+
#include "clang/Analysis/Analyses/DataflowWorklist.h"
1919
#include "clang/Analysis/Analyses/UninitializedValues.h"
2020
#include "clang/Analysis/AnalysisContext.h"
2121
#include "clang/Analysis/CFG.h"
@@ -198,66 +198,6 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
198198
return scratch[idx.getValue()];
199199
}
200200

201-
//------------------------------------------------------------------------====//
202-
// Worklist: worklist for dataflow analysis.
203-
//====------------------------------------------------------------------------//
204-
205-
namespace {
206-
class DataflowWorklist {
207-
PostOrderCFGView::iterator PO_I, PO_E;
208-
SmallVector<const CFGBlock *, 20> worklist;
209-
llvm::BitVector enqueuedBlocks;
210-
public:
211-
DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
212-
: PO_I(view.begin()), PO_E(view.end()),
213-
enqueuedBlocks(cfg.getNumBlockIDs(), true) {
214-
// Treat the first block as already analyzed.
215-
if (PO_I != PO_E) {
216-
assert(*PO_I == &cfg.getEntry());
217-
enqueuedBlocks[(*PO_I)->getBlockID()] = false;
218-
++PO_I;
219-
}
220-
}
221-
222-
void enqueueSuccessors(const CFGBlock *block);
223-
const CFGBlock *dequeue();
224-
};
225-
}
226-
227-
void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
228-
for (CFGBlock::const_succ_iterator I = block->succ_begin(),
229-
E = block->succ_end(); I != E; ++I) {
230-
const CFGBlock *Successor = *I;
231-
if (!Successor || enqueuedBlocks[Successor->getBlockID()])
232-
continue;
233-
worklist.push_back(Successor);
234-
enqueuedBlocks[Successor->getBlockID()] = true;
235-
}
236-
}
237-
238-
const CFGBlock *DataflowWorklist::dequeue() {
239-
const CFGBlock *B = nullptr;
240-
241-
// First dequeue from the worklist. This can represent
242-
// updates along backedges that we want propagated as quickly as possible.
243-
if (!worklist.empty())
244-
B = worklist.pop_back_val();
245-
246-
// Next dequeue from the initial reverse post order. This is the
247-
// theoretical ideal in the presence of no back edges.
248-
else if (PO_I != PO_E) {
249-
B = *PO_I;
250-
++PO_I;
251-
}
252-
else {
253-
return nullptr;
254-
}
255-
256-
assert(enqueuedBlocks[B->getBlockID()] == true);
257-
enqueuedBlocks[B->getBlockID()] = false;
258-
return B;
259-
}
260-
261201
//------------------------------------------------------------------------====//
262202
// Classification of DeclRefExprs as use or initialization.
263203
//====------------------------------------------------------------------------//
@@ -831,7 +771,7 @@ void clang::runUninitializedVariablesAnalysis(
831771
}
832772

833773
// Proceed with the workist.
834-
DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
774+
DataflowWorklist worklist(cfg, ac);
835775
llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
836776
worklist.enqueueSuccessors(&cfg.getEntry());
837777
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);

0 commit comments

Comments
 (0)