summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/CMakeLists.txt2
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp24
-rw-r--r--clang/test/Analysis/analyzer-config.c3
-rw-r--r--clang/test/Analysis/analyzer-config.cpp3
7 files changed, 44 insertions, 4 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 5dd6bdf3849..f8de3bcb59e 100644
--- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -275,6 +275,9 @@ private:
/// \sa shouldWidenLoops
Optional<bool> WidenLoops;
+ /// \sa shouldUnrollLoops
+ Optional<bool> UnrollLoops;
+
/// \sa shouldDisplayNotesAsEvents
Optional<bool> DisplayNotesAsEvents;
@@ -560,7 +563,11 @@ public:
/// This is controlled by the 'widen-loops' config option.
bool shouldWidenLoops();
- /// Returns true if the bug reporter should transparently treat extra note
+ /// Returns true if the analysis should try to unroll loops with known bounds.
+ /// This is controlled by the 'unroll-loops' config option.
+ bool shouldUnrollLoops();
+
+ /// Returns true if the bug reporter should transparently treat extra note
/// diagnostic pieces as event diagnostic pieces. Useful when the diagnostic
/// consumer doesn't support the extra note pieces.
///
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 32040e71163..4a581bddd9c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -272,6 +272,7 @@ void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
reportBug(llvm::to_string(NumTimesReached), BR, N);
}
+ ReachedStats.clear();
}
void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 6f48fcb9e20..d5d6527f4fc 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -375,6 +375,12 @@ bool AnalyzerOptions::shouldWidenLoops() {
return WidenLoops.getValue();
}
+bool AnalyzerOptions::shouldUnrollLoops() {
+ if (!UnrollLoops.hasValue())
+ UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false);
+ return UnrollLoops.getValue();
+}
+
bool AnalyzerOptions::shouldDisplayNotesAsEvents() {
if (!DisplayNotesAsEvents.hasValue())
DisplayNotesAsEvents =
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index 85878f5e96e..5ac4f942f37 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -35,6 +35,7 @@ add_clang_library(clangStaticAnalyzerCore
ExprEngineObjC.cpp
FunctionSummary.cpp
HTMLDiagnostics.cpp
+ LoopUnrolling.cpp
LoopWidening.cpp
MemRegion.cpp
PathDiagnostic.cpp
@@ -54,6 +55,7 @@ add_clang_library(clangStaticAnalyzerCore
LINK_LIBS
clangAST
+ clangASTMatchers
clangAnalysis
clangBasic
clangLex
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index eee5400fe17..409fe173e26 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -17,6 +17,7 @@
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
@@ -27,6 +28,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
@@ -1497,6 +1499,27 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred) {
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+ // If we reach a loop which has a known bound (and meets
+ // other constraints) then consider completely unrolling it.
+ if (AMgr.options.shouldUnrollLoops()) {
+ const CFGBlock *ActualBlock = nodeBuilder.getContext().getBlock();
+ const Stmt *Term = ActualBlock->getTerminator();
+ if (Term && shouldCompletelyUnroll(Term, AMgr.getASTContext())) {
+ ProgramStateRef UnrolledState =
+ markLoopAsUnrolled(Term, Pred->getState(),
+ Pred->getLocationContext()
+ ->getAnalysisDeclContext()
+ ->getCFGStmtMap());
+ if (UnrolledState != Pred->getState())
+ nodeBuilder.generateNode(UnrolledState, Pred);
+ return;
+ }
+
+ if (isUnrolledLoopBlock(ActualBlock, Pred))
+ return;
+ if (ActualBlock->empty())
+ return;
+ }
// If this block is terminated by a loop and it has already been visited the
// maximum number of times, widen the loop.
@@ -1664,7 +1687,6 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
const LocationContext *LCtx = Pred->getLocationContext();
PrettyStackTraceLocationContext StackCrashInfo(LCtx);
currBldrCtx = &BldCtx;
-
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 0d8d34fbf6b..7bed7cb5e3b 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -27,6 +27,7 @@ void foo() {
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 17
+// CHECK-NEXT: num-entries = 18
diff --git a/clang/test/Analysis/analyzer-config.cpp b/clang/test/Analysis/analyzer-config.cpp
index 4166a730cf5..155ee02e839 100644
--- a/clang/test/Analysis/analyzer-config.cpp
+++ b/clang/test/Analysis/analyzer-config.cpp
@@ -38,6 +38,7 @@ public:
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 22
+// CHECK-NEXT: num-entries = 23
OpenPOWER on IntegriCloud