baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: NoQ, szepet, Szelethus.
baloghadamsoftware added a project: clang.
Herald added subscribers: Charusso, gamesh411, donat.nagy, mikhail.ramalho, 
dmgreen, a.sidorin, zzheng, rnkovacs, xazax.hun, whisperity.

For-loops with a variable upper boundary do not differ very much from for-loops 
with integer literals if the value of the variable is known. Unroll these loops 
as well, similarly to them. This was a TODO anyway.


Repository:
  rC Clang

https://reviews.llvm.org/D63279

Files:
  lib/StaticAnalyzer/Core/LoopUnrolling.cpp
  test/Analysis/loop-unrolling.cpp


Index: test/Analysis/loop-unrolling.cpp
===================================================================
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -499,3 +499,15 @@
     clang_analyzer_numTimesReached(); // expected-warning {{6}}
   }
 }
+
+int unroll_known_value_of_variable() {
+  int a[9];
+  int k = 42;
+  int n = 9;
+  for (int i = 0; i < n; i++) {
+    clang_analyzer_numTimesReached(); // expected-warning {{9}}
+    a[i] = 42;
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===================================================================
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -84,9 +84,8 @@
                               hasOperatorName("<="), hasOperatorName(">="),
                               hasOperatorName("!=")),
                         hasEitherOperand(ignoringParenImpCasts(declRefExpr(
-                            
to(varDecl(hasType(isInteger())).bind(BindName))))),
-                        hasEitherOperand(ignoringParenImpCasts(
-                            integerLiteral().bind("boundNum"))))
+                            to(varDecl(hasType(isInteger())).bind(BindName)))
+                                .bind("boundVarOperand"))))
       .bind("conditionOperator");
 }
 
@@ -200,18 +199,40 @@
   if (!isLoopStmt(LoopStmt))
     return false;
 
-  // TODO: Match the cases where the bound is not a concrete literal but an
-  // integer with known value
   auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx);
   if (Matches.empty())
     return false;
 
+  const auto State = Pred->getState();
+  auto &SVB = State->getStateManager().getSValBuilder();
+
   auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName");
-  llvm::APInt BoundNum =
-      Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue();
   llvm::APInt InitNum =
       Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator");
+
+  const Expr *BoundExpr = CondOp->getLHS()->IgnoreParenImpCasts();
+  if (BoundExpr == Matches[0].getNodeAs<Expr>("boundVarOperand"))
+    BoundExpr = CondOp->getRHS()->IgnoreParenImpCasts();
+  SVal BoundNumVal = Pred->getSVal(BoundExpr);
+
+  // If the value of the expression is unknown and it is a declaration
+  // reference then try to get the value of the declaration instead
+  if (BoundNumVal.isUnknown()) {
+    if (const auto *BoundDeclRefExpr = dyn_cast<DeclRefExpr>(BoundExpr)) {
+      // FIXME: Add other declarations such as Objective-C fields
+      if (const auto *BoundVarDecl =
+              dyn_cast<VarDecl>(BoundDeclRefExpr->getDecl())) {
+        BoundNumVal = State->getSVal(
+            State->getLValue(BoundVarDecl, Pred->getLocationContext()));
+      }
+    }
+  }
+  const llvm::APSInt *BoundNumPtr = SVB.getKnownValue(State, BoundNumVal);
+  if (!BoundNumPtr)
+    return false;
+  llvm::APInt BoundNum = *BoundNumPtr;
+
   if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
     InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
     BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());


Index: test/Analysis/loop-unrolling.cpp
===================================================================
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -499,3 +499,15 @@
     clang_analyzer_numTimesReached(); // expected-warning {{6}}
   }
 }
+
+int unroll_known_value_of_variable() {
+  int a[9];
+  int k = 42;
+  int n = 9;
+  for (int i = 0; i < n; i++) {
+    clang_analyzer_numTimesReached(); // expected-warning {{9}}
+    a[i] = 42;
+  }
+  int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+  return 0;
+}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===================================================================
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -84,9 +84,8 @@
                               hasOperatorName("<="), hasOperatorName(">="),
                               hasOperatorName("!=")),
                         hasEitherOperand(ignoringParenImpCasts(declRefExpr(
-                            to(varDecl(hasType(isInteger())).bind(BindName))))),
-                        hasEitherOperand(ignoringParenImpCasts(
-                            integerLiteral().bind("boundNum"))))
+                            to(varDecl(hasType(isInteger())).bind(BindName)))
+                                .bind("boundVarOperand"))))
       .bind("conditionOperator");
 }
 
@@ -200,18 +199,40 @@
   if (!isLoopStmt(LoopStmt))
     return false;
 
-  // TODO: Match the cases where the bound is not a concrete literal but an
-  // integer with known value
   auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx);
   if (Matches.empty())
     return false;
 
+  const auto State = Pred->getState();
+  auto &SVB = State->getStateManager().getSValBuilder();
+
   auto CounterVar = Matches[0].getNodeAs<VarDecl>("initVarName");
-  llvm::APInt BoundNum =
-      Matches[0].getNodeAs<IntegerLiteral>("boundNum")->getValue();
   llvm::APInt InitNum =
       Matches[0].getNodeAs<IntegerLiteral>("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs<BinaryOperator>("conditionOperator");
+
+  const Expr *BoundExpr = CondOp->getLHS()->IgnoreParenImpCasts();
+  if (BoundExpr == Matches[0].getNodeAs<Expr>("boundVarOperand"))
+    BoundExpr = CondOp->getRHS()->IgnoreParenImpCasts();
+  SVal BoundNumVal = Pred->getSVal(BoundExpr);
+
+  // If the value of the expression is unknown and it is a declaration
+  // reference then try to get the value of the declaration instead
+  if (BoundNumVal.isUnknown()) {
+    if (const auto *BoundDeclRefExpr = dyn_cast<DeclRefExpr>(BoundExpr)) {
+      // FIXME: Add other declarations such as Objective-C fields
+      if (const auto *BoundVarDecl =
+              dyn_cast<VarDecl>(BoundDeclRefExpr->getDecl())) {
+        BoundNumVal = State->getSVal(
+            State->getLValue(BoundVarDecl, Pred->getLocationContext()));
+      }
+    }
+  }
+  const llvm::APSInt *BoundNumPtr = SVB.getKnownValue(State, BoundNumVal);
+  if (!BoundNumPtr)
+    return false;
+  llvm::APInt BoundNum = *BoundNumPtr;
+
   if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
     InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
     BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D63279: [Analyzer]... Balogh, Ádám via Phabricator via cfe-commits

Reply via email to