diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h @@ -85,6 +85,7 @@ static std::unique_ptr makeUnexploredFirst(); static std::unique_ptr makeUnexploredFirstPriorityQueue(); static std::unique_ptr makeUnexploredFirstPriorityLocationQueue(); + static std::unique_ptr makeCTUWorkList(); }; } // end ento namespace diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -75,7 +75,7 @@ CoreEngine::CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts) : ExprEng(exprengine), WList(generateWorkList(Opts)), - CTUWList(generateWorkList(Opts)), BCounterFactory(G.getAllocator()), + CTUWList(WorkList::makeCTUWorkList()), BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {} void CoreEngine::setBlockCounter(BlockCounter C) { diff --git a/clang/lib/StaticAnalyzer/Core/WorkList.cpp b/clang/lib/StaticAnalyzer/Core/WorkList.cpp --- a/clang/lib/StaticAnalyzer/Core/WorkList.cpp +++ b/clang/lib/StaticAnalyzer/Core/WorkList.cpp @@ -190,7 +190,9 @@ } namespace { + class UnexploredFirstPriorityQueue : public WorkList { +protected: using BlockID = unsigned; using LocIdentifier = std::pair; @@ -202,7 +204,7 @@ // Compare by number of times the location was visited first (negated // to prefer less often visited locations), then by insertion time (prefer // expanding nodes inserted sooner first). - using QueuePriority = std::pair; + using QueuePriority = std::pair; using QueueItem = std::pair; struct ExplorationComparator { @@ -213,7 +215,7 @@ // Number of inserted nodes, used to emulate DFS ordering in the priority // queue when insertions are equal. - unsigned long Counter = 0; + long Counter = 0; // Number of times a current location was reached. VisitedTimesMap NumReached; @@ -222,12 +224,7 @@ llvm::PriorityQueue, ExplorationComparator> queue; -public: - bool hasWork() const override { - return !queue.empty(); - } - - void enqueue(const WorkListUnit &U) override { + unsigned getNumVisited(const WorkListUnit &U) { const ExplodedNode *N = U.getNode(); unsigned NumVisited = 0; if (auto BE = N->getLocation().getAs()) { @@ -236,7 +233,14 @@ N->getLocationContext()->getStackFrame()); NumVisited = NumReached[LocId]++; } + return NumVisited; + } +public: + bool hasWork() const override { return !queue.empty(); } + + void enqueue(const WorkListUnit &U) override { + unsigned NumVisited = getNumVisited(U); queue.push(std::make_pair(U, std::make_pair(-NumVisited, ++Counter))); } @@ -246,12 +250,41 @@ return U.first; } }; + +class CTUWorkList : public UnexploredFirstPriorityQueue { + enum class SecondaryOrder { DFS = 1, ReverseDFS }; + SecondaryOrder ScndOrd = SecondaryOrder::ReverseDFS; + + long ReverseDFSCounter = 0; + +public: + void enqueue(const WorkListUnit &U) override { + unsigned NumVisited = getNumVisited(U); + queue.push(std::make_pair( + U, std::make_pair(-NumVisited, ScndOrd == SecondaryOrder::DFS + ? ++Counter + : --ReverseDFSCounter))); + } + + WorkListUnit dequeue() override { + // During the first phase we never call dequeue(). Thus, the first call of + // dequeue() indicates the start of the second phase. We want to have the + // normal ordering during the second phase. + ScndOrd = SecondaryOrder::DFS; + return UnexploredFirstPriorityQueue::dequeue(); + } +}; + } // namespace std::unique_ptr WorkList::makeUnexploredFirstPriorityQueue() { return std::make_unique(); } +std::unique_ptr WorkList::makeCTUWorkList() { + return std::make_unique(); +} + namespace { class UnexploredFirstPriorityLocationQueue : public WorkList { using LocIdentifier = const CFGBlock *;