[clang] 05c7dc6 - [DataFlow] Factor two worklist implementations out
Gabor Horvath via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 17 08:11:52 PST 2020
Author: Gabor Horvath
Date: 2020-01-17T08:11:15-08:00
New Revision: 05c7dc66480999574a599ac34d99a4c192d51ba7
URL: https://github.com/llvm/llvm-project/commit/05c7dc66480999574a599ac34d99a4c192d51ba7
DIFF: https://github.com/llvm/llvm-project/commit/05c7dc66480999574a599ac34d99a4c192d51ba7.diff
LOG: [DataFlow] Factor two worklist implementations out
Right now every dataflow algorithm uses its own worklist implementation.
This is a first step to reduce this duplication. Some upcoming
algorithms such as the lifetime analysis is going to use the factored
out implementations.
Differential Revision: https://reviews.llvm.org/D72380
Added:
clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h
Modified:
clang/include/clang/Analysis/FlowSensitive/DataflowValues.h
clang/lib/Analysis/LiveVariables.cpp
clang/lib/Analysis/UninitializedValues.cpp
clang/unittests/Analysis/CFGBuildResult.h
clang/unittests/Analysis/CFGTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h b/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h
index 709753339eb5..68d935c6a400 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h
@@ -168,4 +168,4 @@ class DataflowValues {
};
} // end namespace clang
-#endif
+#endif // LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h b/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h
new file mode 100644
index 000000000000..90095735ad3d
--- /dev/null
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h
@@ -0,0 +1,94 @@
+//===- DataflowWorklist.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A simple and reusable worklist for flow-sensitive analyses.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H
+#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H
+
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/PriorityQueue.h"
+
+namespace clang {
+/// A worklist implementation where the enqueued blocks will be dequeued based
+/// on the order defined by 'Comp'.
+template <typename Comp, unsigned QueueSize> class DataflowWorklistBase {
+ llvm::BitVector EnqueuedBlocks;
+ PostOrderCFGView *POV;
+ llvm::PriorityQueue<const CFGBlock *,
+ SmallVector<const CFGBlock *, QueueSize>, Comp>
+ WorkList;
+
+public:
+ DataflowWorklistBase(const CFG &Cfg, PostOrderCFGView *POV, Comp C)
+ : EnqueuedBlocks(Cfg.getNumBlockIDs()), POV(POV), WorkList(C) {}
+
+ const PostOrderCFGView *getCFGView() const { return POV; }
+
+ void enqueueBlock(const CFGBlock *Block) {
+ if (Block && !EnqueuedBlocks[Block->getBlockID()]) {
+ EnqueuedBlocks[Block->getBlockID()] = true;
+ WorkList.push(Block);
+ }
+ }
+
+ const CFGBlock *dequeue() {
+ if (WorkList.empty())
+ return nullptr;
+ const CFGBlock *B = WorkList.top();
+ WorkList.pop();
+ EnqueuedBlocks[B->getBlockID()] = false;
+ return B;
+ }
+};
+
+struct ReversePostOrderCompare {
+ PostOrderCFGView::BlockOrderCompare Cmp;
+ bool operator()(const CFGBlock *lhs, const CFGBlock *rhs) const {
+ return Cmp(rhs, lhs);
+ }
+};
+
+/// A worklist implementation for forward dataflow analysis. The enqueued
+/// blocks will be dequeued in reverse post order. The worklist cannot contain
+/// the same block multiple times at once.
+struct ForwardDataflowWorklist
+ : DataflowWorklistBase<ReversePostOrderCompare, 20> {
+ ForwardDataflowWorklist(const CFG &Cfg, AnalysisDeclContext &Ctx)
+ : DataflowWorklistBase(
+ Cfg, Ctx.getAnalysis<PostOrderCFGView>(),
+ ReversePostOrderCompare{
+ Ctx.getAnalysis<PostOrderCFGView>()->getComparator()}) {}
+
+ void enqueueSuccessors(const CFGBlock *Block) {
+ for (auto B : Block->succs())
+ enqueueBlock(B);
+ }
+};
+
+/// A worklist implementation for backward dataflow analysis. The enqueued
+/// block will be dequeued in post order. The worklist cannot contain the same
+/// block multiple times at once.
+struct BackwardDataflowWorklist
+ : DataflowWorklistBase<PostOrderCFGView::BlockOrderCompare, 20> {
+ BackwardDataflowWorklist(const CFG &Cfg, AnalysisDeclContext &Ctx)
+ : DataflowWorklistBase(
+ Cfg, Ctx.getAnalysis<PostOrderCFGView>(),
+ Ctx.getAnalysis<PostOrderCFGView>()->getComparator()) {}
+
+ void enqueuePredecessors(const CFGBlock *Block) {
+ for (auto B : Block->preds())
+ enqueueBlock(B);
+ }
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp
index 2cd607d8a493..f910338b0ad3 100644
--- a/clang/lib/Analysis/LiveVariables.cpp
+++ b/clang/lib/Analysis/LiveVariables.cpp
@@ -13,63 +13,16 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/DataflowWorklist.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>
using namespace clang;
-namespace {
-
-class DataflowWorklist {
- 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>()),
- worklist(POV->getComparator()) {}
-
- void enqueueBlock(const CFGBlock *block);
- void enqueuePredecessors(const CFGBlock *block);
-
- const CFGBlock *dequeue();
-};
-
-}
-
-void DataflowWorklist::enqueueBlock(const clang::CFGBlock *block) {
- if (block && !enqueuedBlocks[block->getBlockID()]) {
- enqueuedBlocks[block->getBlockID()] = true;
- worklist.push(block);
- }
-}
-
-void DataflowWorklist::enqueuePredecessors(const clang::CFGBlock *block) {
- for (CFGBlock::const_pred_iterator I = block->pred_begin(),
- E = block->pred_end(); I != E; ++I) {
- enqueueBlock(*I);
- }
-}
-
-const CFGBlock *DataflowWorklist::dequeue() {
- if (worklist.empty())
- return nullptr;
- const CFGBlock *b = worklist.top();
- worklist.pop();
- enqueuedBlocks[b->getBlockID()] = false;
- return b;
-}
-
namespace {
class LiveVariablesImpl {
public:
@@ -136,7 +89,7 @@ namespace {
}
return A;
}
-}
+} // namespace
void LiveVariables::Observer::anchor() { }
@@ -218,7 +171,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
void VisitUnaryOperator(UnaryOperator *UO);
void Visit(Stmt *S);
};
-}
+} // namespace
static const VariableArrayType *FindVA(QualType Ty) {
const Type *ty = Ty.getTypePtr();
@@ -555,7 +508,7 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
// Construct the dataflow worklist. Enqueue the exit block as the
// start of the analysis.
- DataflowWorklist worklist(*cfg, AC);
+ BackwardDataflowWorklist worklist(*cfg, AC);
llvm::BitVector everAnalyzedBlock(cfg->getNumBlockIDs());
// FIXME: we should enqueue using post order.
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 8a233d4a44f1..ff14e18ec144 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -24,6 +24,7 @@
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
@@ -212,68 +213,6 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
return scratch[idx.getValue()];
}
-//------------------------------------------------------------------------====//
-// Worklist: worklist for dataflow analysis.
-//====------------------------------------------------------------------------//
-
-namespace {
-
-class DataflowWorklist {
- PostOrderCFGView::iterator PO_I, PO_E;
- SmallVector<const CFGBlock *, 20> worklist;
- llvm::BitVector enqueuedBlocks;
-
-public:
- DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
- : PO_I(view.begin()), PO_E(view.end()),
- enqueuedBlocks(cfg.getNumBlockIDs(), true) {
- // Treat the first block as already analyzed.
- if (PO_I != PO_E) {
- assert(*PO_I == &cfg.getEntry());
- enqueuedBlocks[(*PO_I)->getBlockID()] = false;
- ++PO_I;
- }
- }
-
- void enqueueSuccessors(const CFGBlock *block);
- const CFGBlock *dequeue();
-};
-
-} // namespace
-
-void DataflowWorklist::enqueueSuccessors(const CFGBlock *block) {
- for (CFGBlock::const_succ_iterator I = block->succ_begin(),
- E = block->succ_end(); I != E; ++I) {
- const CFGBlock *Successor = *I;
- if (!Successor || enqueuedBlocks[Successor->getBlockID()])
- continue;
- worklist.push_back(Successor);
- enqueuedBlocks[Successor->getBlockID()] = true;
- }
-}
-
-const CFGBlock *DataflowWorklist::dequeue() {
- const CFGBlock *B = nullptr;
-
- // First dequeue from the worklist. This can represent
- // updates along backedges that we want propagated as quickly as possible.
- 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.
- else if (PO_I != PO_E) {
- B = *PO_I;
- ++PO_I;
- }
- else
- return nullptr;
-
- assert(enqueuedBlocks[B->getBlockID()] == true);
- enqueuedBlocks[B->getBlockID()] = false;
- return B;
-}
-
//------------------------------------------------------------------------====//
// Classification of DeclRefExprs as use or initialization.
//====------------------------------------------------------------------------//
@@ -924,7 +863,7 @@ void clang::runUninitializedVariablesAnalysis(
}
// Proceed with the workist.
- DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
+ ForwardDataflowWorklist worklist(cfg, ac);
llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
worklist.enqueueSuccessors(&cfg.getEntry());
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
diff --git a/clang/unittests/Analysis/CFGBuildResult.h b/clang/unittests/Analysis/CFGBuildResult.h
index 252e608d28e8..4851d3d7fb6d 100644
--- a/clang/unittests/Analysis/CFGBuildResult.h
+++ b/clang/unittests/Analysis/CFGBuildResult.h
@@ -23,18 +23,21 @@ class BuildResult {
BuiltCFG,
};
- BuildResult(Status S, std::unique_ptr<CFG> Cfg = nullptr,
+ BuildResult(Status S, const FunctionDecl *Func = nullptr,
+ std::unique_ptr<CFG> Cfg = nullptr,
std::unique_ptr<ASTUnit> AST = nullptr)
- : S(S), Cfg(std::move(Cfg)), AST(std::move(AST)) {}
+ : S(S), Cfg(std::move(Cfg)), AST(std::move(AST)), Func(Func) {}
Status getStatus() const { return S; }
CFG *getCFG() const { return Cfg.get(); }
ASTUnit *getAST() const { return AST.get(); }
+ const FunctionDecl *getFunc() const { return Func; }
private:
Status S;
std::unique_ptr<CFG> Cfg;
std::unique_ptr<ASTUnit> AST;
+ const FunctionDecl *Func;
};
class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
@@ -54,7 +57,8 @@ class CFGCallback : public ast_matchers::MatchFinder::MatchCallback {
Options.AddImplicitDtors = true;
if (std::unique_ptr<CFG> Cfg =
CFG::buildCFG(nullptr, Body, Result.Context, Options))
- TheBuildResult = {BuildResult::BuiltCFG, std::move(Cfg), std::move(AST)};
+ TheBuildResult = {BuildResult::BuiltCFG, Func, std::move(Cfg),
+ std::move(AST)};
}
};
diff --git a/clang/unittests/Analysis/CFGTest.cpp b/clang/unittests/Analysis/CFGTest.cpp
index 1994658bed56..1cce8bade42f 100644
--- a/clang/unittests/Analysis/CFGTest.cpp
+++ b/clang/unittests/Analysis/CFGTest.cpp
@@ -7,10 +7,14 @@
//===----------------------------------------------------------------------===//
#include "CFGBuildResult.h"
+#include "clang/AST/Decl.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
+#include <algorithm>
#include <string>
#include <vector>
@@ -73,14 +77,14 @@ TEST(CFG, IsLinear) {
EXPECT_EQ(IsLinear, B.getCFG()->isLinear());
};
- expectLinear(true, "void foo() {}");
- expectLinear(true, "void foo() { if (true) return; }");
- expectLinear(true, "void foo() { if constexpr (false); }");
+ expectLinear(true, "void foo() {}");
+ expectLinear(true, "void foo() { if (true) return; }");
+ expectLinear(true, "void foo() { if constexpr (false); }");
expectLinear(false, "void foo(bool coin) { if (coin) return; }");
expectLinear(false, "void foo() { for(;;); }");
expectLinear(false, "void foo() { do {} while (true); }");
- expectLinear(true, "void foo() { do {} while (false); }");
- expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
+ expectLinear(true, "void foo() { do {} while (false); }");
+ expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
}
TEST(CFG, ElementRefIterator) {
@@ -216,6 +220,54 @@ TEST(CFG, ElementRefIterator) {
EXPECT_EQ(++(CMainBlock->rref_begin()), CMainBlock->rref_begin() + 1);
}
+TEST(CFG, Worklists) {
+ const char *Code = "int f(bool cond) {\n"
+ " int a = 5;\n"
+ " if (cond)\n"
+ " a += 1;\n"
+ " return a;\n"
+ "}\n";
+ BuildResult B = BuildCFG(Code);
+ EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus());
+ const FunctionDecl *Func = B.getFunc();
+ AnalysisDeclContext AC(nullptr, Func);
+ auto *CFG = AC.getCFG();
+
+ std::vector<const CFGBlock *> ReferenceOrder;
+ for (const auto *B : *AC.getAnalysis<PostOrderCFGView>())
+ ReferenceOrder.push_back(B);
+
+ {
+ ForwardDataflowWorklist ForwardWorklist(*CFG, AC);
+ for (const auto *B : *CFG)
+ ForwardWorklist.enqueueBlock(B);
+
+ std::vector<const CFGBlock *> ForwardNodes;
+ while (const CFGBlock *B = ForwardWorklist.dequeue())
+ ForwardNodes.push_back(B);
+
+ EXPECT_EQ(ForwardNodes.size(), ReferenceOrder.size());
+ EXPECT_TRUE(std::equal(ReferenceOrder.begin(), ReferenceOrder.end(),
+ ForwardNodes.begin()));
+ }
+
+ std::reverse(ReferenceOrder.begin(), ReferenceOrder.end());
+
+ {
+ BackwardDataflowWorklist BackwardWorklist(*CFG, AC);
+ for (const auto *B : *CFG)
+ BackwardWorklist.enqueueBlock(B);
+
+ std::vector<const CFGBlock *> BackwardNodes;
+ while (const CFGBlock *B = BackwardWorklist.dequeue())
+ BackwardNodes.push_back(B);
+
+ EXPECT_EQ(BackwardNodes.size(), ReferenceOrder.size());
+ EXPECT_TRUE(std::equal(ReferenceOrder.begin(), ReferenceOrder.end(),
+ BackwardNodes.begin()));
+ }
+}
+
} // namespace
} // namespace analysis
} // namespace clang
More information about the cfe-commits
mailing list