diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h b/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h index e926adf6f0b2a..f1d05743bf7f1 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowWorklist.h @@ -12,6 +12,7 @@ #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWWORKLIST_H +#include "clang/Analysis/Analyses/IntervalPartition.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/CFG.h" #include "llvm/ADT/PriorityQueue.h" @@ -21,16 +22,13 @@ namespace clang { /// on the order defined by 'Comp'. template class DataflowWorklistBase { llvm::BitVector EnqueuedBlocks; - PostOrderCFGView *POV; llvm::PriorityQueue, Comp> WorkList; public: - DataflowWorklistBase(const CFG &Cfg, PostOrderCFGView *POV, Comp C) - : EnqueuedBlocks(Cfg.getNumBlockIDs()), POV(POV), WorkList(C) {} - - const PostOrderCFGView *getCFGView() const { return POV; } + DataflowWorklistBase(const CFG &Cfg, Comp C) + : EnqueuedBlocks(Cfg.getNumBlockIDs()), WorkList(C) {} void enqueueBlock(const CFGBlock *Block) { if (Block && !EnqueuedBlocks[Block->getBlockID()]) { @@ -62,7 +60,7 @@ struct ReversePostOrderCompare { struct ForwardDataflowWorklist : DataflowWorklistBase { ForwardDataflowWorklist(const CFG &Cfg, PostOrderCFGView *POV) - : DataflowWorklistBase(Cfg, POV, + : DataflowWorklistBase(Cfg, ReversePostOrderCompare{POV->getComparator()}) {} ForwardDataflowWorklist(const CFG &Cfg, AnalysisDeclContext &Ctx) @@ -74,6 +72,19 @@ struct ForwardDataflowWorklist } }; +/// A worklist implementation for forward dataflow analysis based on a weak +/// topological ordering of the nodes. The worklist cannot contain the same +/// block multiple times at once. +struct WTODataflowWorklist : DataflowWorklistBase { + WTODataflowWorklist(const CFG &Cfg, const WTOCompare &Cmp) + : DataflowWorklistBase(Cfg, Cmp) {} + + 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. @@ -81,8 +92,7 @@ struct BackwardDataflowWorklist : DataflowWorklistBase { BackwardDataflowWorklist(const CFG &Cfg, AnalysisDeclContext &Ctx) : DataflowWorklistBase( - Cfg, Ctx.getAnalysis(), - Ctx.getAnalysis()->getComparator()) {} + Cfg, Ctx.getAnalysis()->getComparator()) {} void enqueuePredecessors(const CFGBlock *Block) { for (auto B : Block->preds()) diff --git a/clang/unittests/Analysis/CFGTest.cpp b/clang/unittests/Analysis/CFGTest.cpp index 7ce35e3fe4a4f..9fa034a0e472e 100644 --- a/clang/unittests/Analysis/CFGTest.cpp +++ b/clang/unittests/Analysis/CFGTest.cpp @@ -6,13 +6,15 @@ // //===----------------------------------------------------------------------===// +#include "clang/Analysis/CFG.h" #include "CFGBuildResult.h" #include "clang/AST/Decl.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Analysis/Analyses/IntervalPartition.h" #include "clang/Analysis/AnalysisDeclContext.h" -#include "clang/Analysis/CFG.h" #include "clang/Analysis/FlowSensitive/DataflowWorklist.h" #include "clang/Tooling/Tooling.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" #include #include @@ -244,6 +246,8 @@ TEST(CFG, ElementRefIterator) { TEST(CFG, Worklists) { const char *Code = "int f(bool cond) {\n" " int a = 5;\n" + " while (a < 6)\n" + " ++a;\n" " if (cond)\n" " a += 1;\n" " return a;\n" @@ -272,6 +276,30 @@ TEST(CFG, Worklists) { ForwardNodes.begin())); } + // RPO: 876321054 + // WTO: 876534210 + // So, we construct the WTO order accordingly from the reference order. + std::vector WTOOrder = { + ReferenceOrder[0], ReferenceOrder[1], ReferenceOrder[2], + ReferenceOrder[7], ReferenceOrder[3], ReferenceOrder[8], + ReferenceOrder[4], ReferenceOrder[5], ReferenceOrder[6]}; + + { + using ::testing::ElementsAreArray; + std::optional WTO = getIntervalWTO(*CFG); + ASSERT_TRUE(WTO); + WTOCompare WCmp(*WTO); + WTODataflowWorklist WTOWorklist(*CFG, WCmp); + for (const auto *B : *CFG) + WTOWorklist.enqueueBlock(B); + + std::vector WTONodes; + while (const CFGBlock *B = WTOWorklist.dequeue()) + WTONodes.push_back(B); + + EXPECT_THAT(WTONodes, ElementsAreArray(WTOOrder)); + } + std::reverse(ReferenceOrder.begin(), ReferenceOrder.end()); {