r328280 - [analyzer] [NFC] Move worklist implementation to WorkList.cpp
George Karpenkov via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 22 17:16:01 PDT 2018
Author: george.karpenkov
Date: Thu Mar 22 17:16:01 2018
New Revision: 328280
URL: http://llvm.org/viewvc/llvm-project?rev=328280&view=rev
Log:
[analyzer] [NFC] Move worklist implementation to WorkList.cpp
Current location is very confusing, especially because there is already
WorkList.h, and other code in CoreEngine.cpp is not related to work list
implementation.
Differential Revision: https://reviews.llvm.org/D44759
Added:
cfe/trunk/lib/StaticAnalyzer/Core/WorkList.cpp
Modified:
cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt
cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt?rev=328280&r1=328279&r2=328280&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt Thu Mar 22 17:16:01 2018
@@ -51,6 +51,7 @@ add_clang_library(clangStaticAnalyzerCor
Store.cpp
SubEngine.cpp
SymbolManager.cpp
+ WorkList.cpp
Z3ConstraintManager.cpp
LINK_LIBS
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp?rev=328280&r1=328279&r2=328280&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp Thu Mar 22 17:16:01 2018
@@ -27,21 +27,15 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/PriorityQueue.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
-#include <deque>
#include <memory>
#include <utility>
-#include <vector>
using namespace clang;
using namespace ento;
@@ -55,230 +49,6 @@ STATISTIC(NumReachedMaxSteps,
STATISTIC(NumPathsExplored,
"The # of paths explored by the analyzer.");
-STATISTIC(MaxQueueSize, "Maximum size of the worklist");
-STATISTIC(MaxReachableSize, "Maximum size of auxiliary worklist set");
-
-//===----------------------------------------------------------------------===//
-// Worklist classes for exploration of reachable states.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class DFS : public WorkList {
- SmallVector<WorkListUnit, 20> Stack;
-
-public:
- bool hasWork() const override {
- return !Stack.empty();
- }
-
- void enqueue(const WorkListUnit& U) override {
- Stack.push_back(U);
- }
-
- WorkListUnit dequeue() override {
- assert(!Stack.empty());
- const WorkListUnit& U = Stack.back();
- Stack.pop_back(); // This technically "invalidates" U, but we are fine.
- return U;
- }
-};
-
-class BFS : public WorkList {
- std::deque<WorkListUnit> Queue;
-
-public:
- bool hasWork() const override {
- return !Queue.empty();
- }
-
- void enqueue(const WorkListUnit& U) override {
- Queue.push_back(U);
- }
-
- WorkListUnit dequeue() override {
- WorkListUnit U = Queue.front();
- Queue.pop_front();
- return U;
- }
-};
-
-} // namespace
-
-// Place the dstor for WorkList here because it contains virtual member
-// functions, and we the code for the dstor generated in one compilation unit.
-WorkList::~WorkList() = default;
-
-std::unique_ptr<WorkList> WorkList::makeDFS() {
- return llvm::make_unique<DFS>();
-}
-
-std::unique_ptr<WorkList> WorkList::makeBFS() {
- return llvm::make_unique<BFS>();
-}
-
-namespace {
-
- class BFSBlockDFSContents : public WorkList {
- std::deque<WorkListUnit> Queue;
- SmallVector<WorkListUnit, 20> Stack;
-
- public:
- bool hasWork() const override {
- return !Queue.empty() || !Stack.empty();
- }
-
- void enqueue(const WorkListUnit& U) override {
- if (U.getNode()->getLocation().getAs<BlockEntrance>())
- Queue.push_front(U);
- else
- Stack.push_back(U);
- }
-
- WorkListUnit dequeue() override {
- // Process all basic blocks to completion.
- if (!Stack.empty()) {
- const WorkListUnit& U = Stack.back();
- Stack.pop_back(); // This technically "invalidates" U, but we are fine.
- return U;
- }
-
- assert(!Queue.empty());
- // Don't use const reference. The subsequent pop_back() might make it
- // unsafe.
- WorkListUnit U = Queue.front();
- Queue.pop_front();
- return U;
- }
- };
-
-} // namespace
-
-std::unique_ptr<WorkList> WorkList::makeBFSBlockDFSContents() {
- return llvm::make_unique<BFSBlockDFSContents>();
-}
-
-namespace {
-
-class UnexploredFirstStack : public WorkList {
- /// Stack of nodes known to have statements we have not traversed yet.
- SmallVector<WorkListUnit, 20> StackUnexplored;
-
- /// Stack of all other nodes.
- SmallVector<WorkListUnit, 20> StackOthers;
-
- using BlockID = unsigned;
- using LocIdentifier = std::pair<BlockID, const StackFrameContext *>;
-
- llvm::DenseSet<LocIdentifier> Reachable;
-
-public:
- bool hasWork() const override {
- return !(StackUnexplored.empty() && StackOthers.empty());
- }
-
- void enqueue(const WorkListUnit &U) override {
- const ExplodedNode *N = U.getNode();
- auto BE = N->getLocation().getAs<BlockEntrance>();
-
- if (!BE) {
- // Assume the choice of the order of the preceeding block entrance was
- // correct.
- StackUnexplored.push_back(U);
- } else {
- LocIdentifier LocId = std::make_pair(
- BE->getBlock()->getBlockID(), N->getStackFrame());
- auto InsertInfo = Reachable.insert(LocId);
-
- if (InsertInfo.second) {
- StackUnexplored.push_back(U);
- } else {
- StackOthers.push_back(U);
- }
- }
- MaxReachableSize.updateMax(Reachable.size());
- MaxQueueSize.updateMax(StackUnexplored.size() + StackOthers.size());
- }
-
- WorkListUnit dequeue() override {
- if (!StackUnexplored.empty()) {
- WorkListUnit &U = StackUnexplored.back();
- StackUnexplored.pop_back();
- return U;
- } else {
- WorkListUnit &U = StackOthers.back();
- StackOthers.pop_back();
- return U;
- }
- }
-};
-
-} // namespace
-
-std::unique_ptr<WorkList> WorkList::makeUnexploredFirst() {
- return llvm::make_unique<UnexploredFirstStack>();
-}
-
-class UnexploredFirstPriorityQueue : public WorkList {
- using BlockID = unsigned;
- using LocIdentifier = std::pair<BlockID, const StackFrameContext *>;
-
- // How many times each location was visited.
- // Is signed because we negate it later in order to have a reversed
- // comparison.
- using VisitedTimesMap = llvm::DenseMap<LocIdentifier, int>;
-
- // 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<int, unsigned long>;
- using QueueItem = std::pair<WorkListUnit, QueuePriority>;
-
- struct ExplorationComparator {
- bool operator() (const QueueItem &LHS, const QueueItem &RHS) {
- return LHS.second < RHS.second;
- }
- };
-
- // Number of inserted nodes, used to emulate DFS ordering in the priority
- // queue when insertions are equal.
- unsigned long Counter = 0;
-
- // Number of times a current location was reached.
- VisitedTimesMap NumReached;
-
- // The top item is the largest one.
- llvm::PriorityQueue<QueueItem, std::vector<QueueItem>, ExplorationComparator>
- queue;
-
-public:
- bool hasWork() const override {
- return !queue.empty();
- }
-
- void enqueue(const WorkListUnit &U) override {
- const ExplodedNode *N = U.getNode();
- unsigned NumVisited = 0;
- if (auto BE = N->getLocation().getAs<BlockEntrance>()) {
- LocIdentifier LocId = std::make_pair(
- BE->getBlock()->getBlockID(), N->getStackFrame());
- NumVisited = NumReached[LocId]++;
- }
-
- queue.push(std::make_pair(U, std::make_pair(-NumVisited, ++Counter)));
- }
-
- WorkListUnit dequeue() override {
- QueueItem U = queue.top();
- queue.pop();
- return U.first;
- }
-};
-
-std::unique_ptr<WorkList> WorkList::makeUnexploredFirstPriorityQueue() {
- return llvm::make_unique<UnexploredFirstPriorityQueue>();
-}
-
//===----------------------------------------------------------------------===//
// Core analysis engine.
//===----------------------------------------------------------------------===//
Added: cfe/trunk/lib/StaticAnalyzer/Core/WorkList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/WorkList.cpp?rev=328280&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/WorkList.cpp (added)
+++ cfe/trunk/lib/StaticAnalyzer/Core/WorkList.cpp Thu Mar 22 17:16:01 2018
@@ -0,0 +1,252 @@
+//===- WorkList.cpp - Analyzer work-list implementation--------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines different worklist implementations for the static analyzer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
+#include "llvm/ADT/PriorityQueue.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Statistic.h"
+#include <deque>
+#include <vector>
+
+using namespace clang;
+using namespace ento;
+
+#define DEBUG_TYPE "WorkList"
+
+STATISTIC(MaxQueueSize, "Maximum size of the worklist");
+STATISTIC(MaxReachableSize, "Maximum size of auxiliary worklist set");
+
+//===----------------------------------------------------------------------===//
+// Worklist classes for exploration of reachable states.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class DFS : public WorkList {
+ SmallVector<WorkListUnit, 20> Stack;
+
+public:
+ bool hasWork() const override {
+ return !Stack.empty();
+ }
+
+ void enqueue(const WorkListUnit& U) override {
+ Stack.push_back(U);
+ }
+
+ WorkListUnit dequeue() override {
+ assert(!Stack.empty());
+ const WorkListUnit& U = Stack.back();
+ Stack.pop_back(); // This technically "invalidates" U, but we are fine.
+ return U;
+ }
+};
+
+class BFS : public WorkList {
+ std::deque<WorkListUnit> Queue;
+
+public:
+ bool hasWork() const override {
+ return !Queue.empty();
+ }
+
+ void enqueue(const WorkListUnit& U) override {
+ Queue.push_back(U);
+ }
+
+ WorkListUnit dequeue() override {
+ WorkListUnit U = Queue.front();
+ Queue.pop_front();
+ return U;
+ }
+};
+
+} // namespace
+
+// Place the dstor for WorkList here because it contains virtual member
+// functions, and we the code for the dstor generated in one compilation unit.
+WorkList::~WorkList() = default;
+
+std::unique_ptr<WorkList> WorkList::makeDFS() {
+ return llvm::make_unique<DFS>();
+}
+
+std::unique_ptr<WorkList> WorkList::makeBFS() {
+ return llvm::make_unique<BFS>();
+}
+
+namespace {
+
+ class BFSBlockDFSContents : public WorkList {
+ std::deque<WorkListUnit> Queue;
+ SmallVector<WorkListUnit, 20> Stack;
+
+ public:
+ bool hasWork() const override {
+ return !Queue.empty() || !Stack.empty();
+ }
+
+ void enqueue(const WorkListUnit& U) override {
+ if (U.getNode()->getLocation().getAs<BlockEntrance>())
+ Queue.push_front(U);
+ else
+ Stack.push_back(U);
+ }
+
+ WorkListUnit dequeue() override {
+ // Process all basic blocks to completion.
+ if (!Stack.empty()) {
+ const WorkListUnit& U = Stack.back();
+ Stack.pop_back(); // This technically "invalidates" U, but we are fine.
+ return U;
+ }
+
+ assert(!Queue.empty());
+ // Don't use const reference. The subsequent pop_back() might make it
+ // unsafe.
+ WorkListUnit U = Queue.front();
+ Queue.pop_front();
+ return U;
+ }
+ };
+
+} // namespace
+
+std::unique_ptr<WorkList> WorkList::makeBFSBlockDFSContents() {
+ return llvm::make_unique<BFSBlockDFSContents>();
+}
+
+namespace {
+
+class UnexploredFirstStack : public WorkList {
+ /// Stack of nodes known to have statements we have not traversed yet.
+ SmallVector<WorkListUnit, 20> StackUnexplored;
+
+ /// Stack of all other nodes.
+ SmallVector<WorkListUnit, 20> StackOthers;
+
+ using BlockID = unsigned;
+ using LocIdentifier = std::pair<BlockID, const StackFrameContext *>;
+
+ llvm::DenseSet<LocIdentifier> Reachable;
+
+public:
+ bool hasWork() const override {
+ return !(StackUnexplored.empty() && StackOthers.empty());
+ }
+
+ void enqueue(const WorkListUnit &U) override {
+ const ExplodedNode *N = U.getNode();
+ auto BE = N->getLocation().getAs<BlockEntrance>();
+
+ if (!BE) {
+ // Assume the choice of the order of the preceeding block entrance was
+ // correct.
+ StackUnexplored.push_back(U);
+ } else {
+ LocIdentifier LocId = std::make_pair(
+ BE->getBlock()->getBlockID(),
+ N->getLocationContext()->getCurrentStackFrame());
+ auto InsertInfo = Reachable.insert(LocId);
+
+ if (InsertInfo.second) {
+ StackUnexplored.push_back(U);
+ } else {
+ StackOthers.push_back(U);
+ }
+ }
+ MaxReachableSize.updateMax(Reachable.size());
+ MaxQueueSize.updateMax(StackUnexplored.size() + StackOthers.size());
+ }
+
+ WorkListUnit dequeue() override {
+ if (!StackUnexplored.empty()) {
+ WorkListUnit &U = StackUnexplored.back();
+ StackUnexplored.pop_back();
+ return U;
+ } else {
+ WorkListUnit &U = StackOthers.back();
+ StackOthers.pop_back();
+ return U;
+ }
+ }
+};
+
+} // namespace
+
+std::unique_ptr<WorkList> WorkList::makeUnexploredFirst() {
+ return llvm::make_unique<UnexploredFirstStack>();
+}
+
+class UnexploredFirstPriorityQueue : public WorkList {
+ using BlockID = unsigned;
+ using LocIdentifier = std::pair<BlockID, const StackFrameContext *>;
+
+ // How many times each location was visited.
+ // Is signed because we negate it later in order to have a reversed
+ // comparison.
+ using VisitedTimesMap = llvm::DenseMap<LocIdentifier, int>;
+
+ // 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<int, unsigned long>;
+ using QueueItem = std::pair<WorkListUnit, QueuePriority>;
+
+ struct ExplorationComparator {
+ bool operator() (const QueueItem &LHS, const QueueItem &RHS) {
+ return LHS.second < RHS.second;
+ }
+ };
+
+ // Number of inserted nodes, used to emulate DFS ordering in the priority
+ // queue when insertions are equal.
+ unsigned long Counter = 0;
+
+ // Number of times a current location was reached.
+ VisitedTimesMap NumReached;
+
+ // The top item is the largest one.
+ llvm::PriorityQueue<QueueItem, std::vector<QueueItem>, ExplorationComparator>
+ queue;
+
+public:
+ bool hasWork() const override {
+ return !queue.empty();
+ }
+
+ void enqueue(const WorkListUnit &U) override {
+ const ExplodedNode *N = U.getNode();
+ unsigned NumVisited = 0;
+ if (auto BE = N->getLocation().getAs<BlockEntrance>()) {
+ LocIdentifier LocId = std::make_pair(
+ BE->getBlock()->getBlockID(),
+ N->getLocationContext()->getCurrentStackFrame());
+ NumVisited = NumReached[LocId]++;
+ }
+
+ queue.push(std::make_pair(U, std::make_pair(-NumVisited, ++Counter)));
+ }
+
+ WorkListUnit dequeue() override {
+ QueueItem U = queue.top();
+ queue.pop();
+ return U.first;
+ }
+};
+
+std::unique_ptr<WorkList> WorkList::makeUnexploredFirstPriorityQueue() {
+ return llvm::make_unique<UnexploredFirstPriorityQueue>();
+}
More information about the cfe-commits
mailing list