r311883 - [StaticAnalyzer] LoopUnrolling: Keep track the maximum number of steps for each loop
Peter Szecsi via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 28 03:50:28 PDT 2017
Author: szepet
Date: Mon Aug 28 03:50:28 2017
New Revision: 311883
URL: http://llvm.org/viewvc/llvm-project?rev=311883&view=rev
Log:
[StaticAnalyzer] LoopUnrolling: Keep track the maximum number of steps for each loop
This way the unrolling can be restricted for loops which will take at most a
given number of steps. It is defined as 128 in this patch and it seems to have
a good number for that purpose.
Differential Revision: https://reviews.llvm.org/D37181
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
cfe/trunk/test/Analysis/loop-unrolling.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h?rev=311883&r1=311882&r2=311883&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h Mon Aug 28 03:50:28 2017
@@ -38,7 +38,7 @@ bool isUnrolledState(ProgramStateRef Sta
/// Updates the stack of loops contained by the ProgramState.
ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
- ExplodedNode* Pred);
+ ExplodedNode* Pred, unsigned maxVisitOnPath);
/// Updates the given ProgramState. In current implementation it removes the top
/// element of the stack of loops.
Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=311883&r1=311882&r2=311883&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Mon Aug 28 03:50:28 2017
@@ -1523,10 +1523,11 @@ void ExprEngine::processCFGBlockEntrance
// If we reach a loop which has a known bound (and meets
// other constraints) then consider completely unrolling it.
if(AMgr.options.shouldUnrollLoops()) {
+ unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
if (Term) {
ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
- Pred);
+ Pred, maxBlockVisitOnPath);
if (NewState != Pred->getState()) {
ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
if (!UpdatedNode)
Modified: cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp?rev=311883&r1=311882&r2=311883&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/LoopUnrolling.cpp Mon Aug 28 03:50:28 2017
@@ -23,22 +23,28 @@ using namespace clang;
using namespace ento;
using namespace clang::ast_matchers;
+static const int MAXIMUM_STEP_UNROLLED = 128;
+
struct LoopState {
private:
enum Kind { Normal, Unrolled } K;
const Stmt *LoopStmt;
const LocationContext *LCtx;
- LoopState(Kind InK, const Stmt *S, const LocationContext *L)
- : K(InK), LoopStmt(S), LCtx(L) {}
+ unsigned maxStep;
+ LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
+ : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
public:
- static LoopState getNormal(const Stmt *S, const LocationContext *L) {
- return LoopState(Normal, S, L);
+ static LoopState getNormal(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+ return LoopState(Normal, S, L, N);
}
- static LoopState getUnrolled(const Stmt *S, const LocationContext *L) {
- return LoopState(Unrolled, S, L);
+ static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
+ unsigned N) {
+ return LoopState(Unrolled, S, L, N);
}
bool isUnrolled() const { return K == Unrolled; }
+ unsigned getMaxStep() const { return maxStep; }
const Stmt *getLoopStmt() const { return LoopStmt; }
const LocationContext *getLocationContext() const { return LCtx; }
bool operator==(const LoopState &X) const {
@@ -48,6 +54,7 @@ public:
ID.AddInteger(K);
ID.AddPointer(LoopStmt);
ID.AddPointer(LCtx);
+ ID.AddInteger(maxStep);
}
};
@@ -74,12 +81,14 @@ ProgramStateRef processLoopEnd(const Stm
}
static internal::Matcher<Stmt> simpleCondition(StringRef BindName) {
- return binaryOperator(
- anyOf(hasOperatorName("<"), hasOperatorName(">"), hasOperatorName("<="),
- hasOperatorName(">="), hasOperatorName("!=")),
- hasEitherOperand(ignoringParenImpCasts(
- declRefExpr(to(varDecl(hasType(isInteger())).bind(BindName))))),
- hasEitherOperand(ignoringParenImpCasts(integerLiteral())));
+ return binaryOperator(anyOf(hasOperatorName("<"), hasOperatorName(">"),
+ hasOperatorName("<="), hasOperatorName(">="),
+ hasOperatorName("!=")),
+ hasEitherOperand(ignoringParenImpCasts(declRefExpr(
+ to(varDecl(hasType(isInteger())).bind(BindName))))),
+ hasEitherOperand(ignoringParenImpCasts(
+ integerLiteral().bind("boundNum"))))
+ .bind("conditionOperator");
}
static internal::Matcher<Stmt>
@@ -134,13 +143,13 @@ static internal::Matcher<Stmt> forLoopMa
return forStmt(
hasCondition(simpleCondition("initVarName")),
// Initialization should match the form: 'int i = 6' or 'i = 42'.
- hasLoopInit(
- anyOf(declStmt(hasSingleDecl(
- varDecl(allOf(hasInitializer(integerLiteral()),
- equalsBoundNode("initVarName"))))),
- binaryOperator(hasLHS(declRefExpr(to(varDecl(
- equalsBoundNode("initVarName"))))),
- hasRHS(integerLiteral())))),
+ hasLoopInit(anyOf(
+ declStmt(hasSingleDecl(varDecl(
+ allOf(hasInitializer(integerLiteral().bind("initNum")),
+ equalsBoundNode("initVarName"))))),
+ binaryOperator(hasLHS(declRefExpr(to(
+ varDecl(equalsBoundNode("initVarName"))))),
+ hasRHS(integerLiteral().bind("initNum"))))),
// Incrementation should be a simple increment or decrement
// operator call.
hasIncrement(unaryOperator(
@@ -187,7 +196,7 @@ static bool isPossiblyEscaped(const VarD
}
bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
- ExplodedNode *Pred) {
+ ExplodedNode *Pred, unsigned &maxStep) {
if (!isLoopStmt(LoopStmt))
return false;
@@ -199,15 +208,21 @@ bool shouldCompletelyUnroll(const Stmt *
return false;
auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName");
+ auto BoundNum = Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue();
+ auto InitNum = Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue();
+ auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator");
+ if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
+ maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
+ else
+ maxStep = (BoundNum - InitNum).abs().getZExtValue();
// Check if the counter of the loop is not escaped before.
return !isPossiblyEscaped(CounterVar->getCanonicalDecl(), Pred);
}
-bool madeNewBranch(ExplodedNode* N, const Stmt* LoopStmt) {
- const Stmt* S = nullptr;
- while (!N->pred_empty())
- {
+bool madeNewBranch(ExplodedNode *N, const Stmt *LoopStmt) {
+ const Stmt *S = nullptr;
+ while (!N->pred_empty()) {
if (N->succ_size() > 1)
return true;
@@ -226,7 +241,7 @@ bool madeNewBranch(ExplodedNode* N, cons
// updateLoopStack is called on every basic block, therefore it needs to be fast
ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
- ExplodedNode* Pred) {
+ ExplodedNode *Pred, unsigned maxVisitOnPath) {
auto State = Pred->getState();
auto LCtx = Pred->getLocationContext();
@@ -238,17 +253,27 @@ ProgramStateRef updateLoopStack(const St
LCtx == LS.getHead().getLocationContext()) {
if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) {
State = State->set<LoopStack>(LS.getTail());
- State = State->add<LoopStack>(LoopState::getNormal(LoopStmt, LCtx));
+ State = State->add<LoopStack>(
+ LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
}
return State;
}
-
- if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred)) {
- State = State->add<LoopStack>(LoopState::getNormal(LoopStmt, LCtx));
+ unsigned maxStep;
+ if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, maxStep)) {
+ State = State->add<LoopStack>(
+ LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
return State;
}
- State = State->add<LoopStack>(LoopState::getUnrolled(LoopStmt, LCtx));
+ unsigned outerStep = (LS.isEmpty() ? 1 : LS.getHead().getMaxStep());
+
+ unsigned innerMaxStep = maxStep * outerStep;
+ if (innerMaxStep > MAXIMUM_STEP_UNROLLED)
+ State = State->add<LoopStack>(
+ LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
+ else
+ State = State->add<LoopStack>(
+ LoopState::getUnrolled(LoopStmt, LCtx, innerMaxStep));
return State;
}
Modified: cfe/trunk/test/Analysis/loop-unrolling.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/loop-unrolling.cpp?rev=311883&r1=311882&r2=311883&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/loop-unrolling.cpp (original)
+++ cfe/trunk/test/Analysis/loop-unrolling.cpp Mon Aug 28 03:50:28 2017
@@ -5,7 +5,7 @@ void clang_analyzer_warnIfReached();
int getNum();
void foo(int &);
-// Testing for loops.
+
int simple_unroll1() {
int a[9];
int k = 42;
@@ -259,7 +259,6 @@ int nested_inlined_no_unroll1() {
return 0;
}
-
int recursion_unroll1(bool b) {
int k = 2;
for (int i = 0; i < 5; i++) {
@@ -289,7 +288,7 @@ int recursion_unroll3(bool b) {
int k = 2;
for (int i = 0; i < 5; i++) {
clang_analyzer_numTimesReached(); // expected-warning {{10}}
- if(i == 4 && b) {
+ if (i == 4 && b) {
recursion_unroll3(false);
break;
}
@@ -320,3 +319,57 @@ int loop_exit_while_empty_loop_stack() {
return 0;
}
+int num_steps_on_limit() {
+ for (int i = 0; i < 128; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ return 0;
+}
+
+int num_steps_over_limit1() {
+ for (int i = 0; i < 129; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ return 0;
+}
+
+int num_steps_on_limit2() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 64; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_over_limit2() {
+ for (int i = 0; i < 2; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (int j = 0; j <= 64; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_on_limit3() {
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ for (int j = 0; j < 32; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_over_limit3() {
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (int j = 0; j < 33; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ }
+ return 0;
+}
+
More information about the cfe-commits
mailing list