r311235 - [CFG] Add LoopExit information to CFG

Peter Szecsi via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 19 04:19:16 PDT 2017


Author: szepet
Date: Sat Aug 19 04:19:16 2017
New Revision: 311235

URL: http://llvm.org/viewvc/llvm-project?rev=311235&view=rev
Log:
[CFG] Add LoopExit information to CFG

This patch introduces a new CFG element CFGLoopExit that indicate when a loop
ends. It does not deal with returnStmts yet (left it as a TODO).
It hidden behind a new analyzer-config flag called cfg-loopexit (false by
default).
Test cases added.

The main purpose of this patch right know is to make loop unrolling and loop
widening easier and more efficient. However, this information can be useful for
future improvements in the StaticAnalyzer core too.

Differential Revision: https://reviews.llvm.org/D35668


Added:
    cfe/trunk/test/Analysis/loopexit-cfg-output.cpp
Modified:
    cfe/trunk/include/clang/Analysis/AnalysisContext.h
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
    cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
    cfe/trunk/test/Analysis/analyzer-config.c
    cfe/trunk/test/Analysis/analyzer-config.cpp

Modified: cfe/trunk/include/clang/Analysis/AnalysisContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisContext.h?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/AnalysisContext.h (original)
+++ cfe/trunk/include/clang/Analysis/AnalysisContext.h Sat Aug 19 04:19:16 2017
@@ -427,6 +427,7 @@ public:
                              bool addInitializers = false,
                              bool addTemporaryDtors = false,
                              bool addLifetime = false,
+                             bool addLoopExit = false,
                              bool synthesizeBodies = false,
                              bool addStaticInitBranches = false,
                              bool addCXXNewAllocator = true,

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Sat Aug 19 04:19:16 2017
@@ -59,6 +59,7 @@ public:
     Initializer,
     NewAllocator,
     LifetimeEnds,
+    LoopExit,
     // dtor kind
     AutomaticObjectDtor,
     DeleteDtor,
@@ -168,6 +169,29 @@ private:
   }
 };
 
+/// Represents the point where a loop ends.
+/// This element is is only produced when building the CFG for the static
+/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag.
+///
+/// Note: a loop exit element can be reached even when the loop body was never
+/// entered.
+class CFGLoopExit : public CFGElement {
+public:
+    explicit CFGLoopExit(const Stmt *stmt)
+            : CFGElement(LoopExit, stmt) {}
+
+    const Stmt *getLoopStmt() const {
+      return static_cast<Stmt *>(Data1.getPointer());
+    }
+
+private:
+    friend class CFGElement;
+    CFGLoopExit() {}
+    static bool isKind(const CFGElement &elem) {
+      return elem.getKind() == LoopExit;
+    }
+};
+
 /// Represents the point where the lifetime of an automatic object ends
 class CFGLifetimeEnds : public CFGElement {
 public:
@@ -728,6 +752,10 @@ public:
     Elements.push_back(CFGLifetimeEnds(VD, S), C);
   }
 
+  void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) {
+    Elements.push_back(CFGLoopExit(LoopStmt), C);
+  }
+
   void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
     Elements.push_back(CFGDeleteDtor(RD, DE), C);
   }
@@ -794,6 +822,7 @@ public:
     bool AddInitializers;
     bool AddImplicitDtors;
     bool AddLifetime;
+    bool AddLoopExit;
     bool AddTemporaryDtors;
     bool AddStaticInitBranches;
     bool AddCXXNewAllocator;
@@ -818,7 +847,7 @@ public:
         PruneTriviallyFalseEdges(true),
         AddEHEdges(false),
         AddInitializers(false), AddImplicitDtors(false),
-        AddLifetime(false),
+        AddLifetime(false), AddLoopExit(false),
         AddTemporaryDtors(false), AddStaticInitBranches(false),
         AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
   };

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Sat Aug 19 04:19:16 2017
@@ -214,6 +214,9 @@ private:
   /// \sa IncludeLifetimeInCFG
   Optional<bool> IncludeLifetimeInCFG;
 
+  /// \sa IncludeLoopExitInCFG
+  Optional<bool> IncludeLoopExitInCFG;
+
   /// \sa mayInlineCXXStandardLibrary
   Optional<bool> InlineCXXStandardLibrary;
   
@@ -418,6 +421,13 @@ public:
   /// the values "true" and "false".
   bool includeLifetimeInCFG();
 
+  /// Returns whether or not the end of the loop information should be included
+  /// in the CFG.
+  ///
+  /// This is controlled by the 'cfg-loopexit' config option, which accepts
+  /// the values "true" and "false".
+  bool includeLoopExitInCFG();
+
   /// Returns whether or not C++ standard library functions may be considered
   /// for inlining.
   ///

Modified: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp (original)
+++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp Sat Aug 19 04:19:16 2017
@@ -68,6 +68,7 @@ AnalysisDeclContextManager::AnalysisDecl
                                                        bool addInitializers,
                                                        bool addTemporaryDtors,
                                                        bool addLifetime,
+                                                       bool addLoopExit,
                                                        bool synthesizeBodies,
                                                        bool addStaticInitBranch,
                                                        bool addCXXNewAllocator,
@@ -79,6 +80,7 @@ AnalysisDeclContextManager::AnalysisDecl
   cfgBuildOptions.AddInitializers = addInitializers;
   cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
   cfgBuildOptions.AddLifetime = addLifetime;
+  cfgBuildOptions.AddLoopExit = addLoopExit;
   cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
   cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
 }

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Sat Aug 19 04:19:16 2017
@@ -602,6 +602,7 @@ private:
     return Visit(S, AddStmtChoice::AlwaysAdd);
   }
   CFGBlock *addInitializer(CXXCtorInitializer *I);
+  void addLoopExit(const Stmt *LoopStmt);
   void addAutomaticObjDtors(LocalScope::const_iterator B,
                             LocalScope::const_iterator E, Stmt *S);
   void addLifetimeEnds(LocalScope::const_iterator B,
@@ -652,6 +653,10 @@ private:
     B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
   }
 
+  void appendLoopExit(CFGBlock *B, const Stmt *LoopStmt) {
+    B->appendLoopExit(LoopStmt, cfg->getBumpVectorContext());
+  }
+
   void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
     B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
   }
@@ -1253,6 +1258,16 @@ static QualType getReferenceInitTemporar
   return Init->getType();
 }
 
+
+// TODO: Support adding LoopExit element to the CFG in case where the loop is
+// ended by ReturnStmt, GotoStmt or ThrowExpr.
+void CFGBuilder::addLoopExit(const Stmt *LoopStmt){
+  if(!BuildOpts.AddLoopExit)
+    return;
+  autoCreateBlock();
+  appendLoopExit(Block, LoopStmt);
+}
+
 void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
                                          LocalScope::const_iterator E,
                                          Stmt *S) {
@@ -2543,6 +2558,8 @@ CFGBlock *CFGBuilder::VisitForStmt(ForSt
 
   addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
 
+  addLoopExit(F);
+
   // "for" is a control-flow statement.  Thus we stop processing the current
   // block.
   if (Block) {
@@ -2882,6 +2899,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(Whi
     addLocalScopeForVarDecl(VD);
     addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
   }
+  addLoopExit(W);
 
   // "while" is a control-flow statement.  Thus we stop processing the current
   // block.
@@ -3045,6 +3063,8 @@ CFGBlock *CFGBuilder::VisitCXXThrowExpr(
 CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
   CFGBlock *LoopSuccessor = nullptr;
 
+  addLoopExit(D);
+
   // "do...while" is a control-flow statement.  Thus we stop processing the
   // current block.
   if (Block) {
@@ -4025,6 +4045,7 @@ CFGImplicitDtor::getDestructorDecl(ASTCo
     case CFGElement::Statement:
     case CFGElement::Initializer:
     case CFGElement::NewAllocator:
+    case CFGElement::LoopExit:
     case CFGElement::LifetimeEnds:
       llvm_unreachable("getDestructorDecl should only be used with "
                        "ImplicitDtors");
@@ -4442,6 +4463,9 @@ static void print_elem(raw_ostream &OS,
 
     OS << " (Lifetime ends)\n";
 
+  } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) {
+    const Stmt *LoopStmt = LE->getLoopStmt();
+    OS << LoopStmt->getStmtClassName() << " (LoopExit)\n";
   } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
     OS << "CFGNewAllocator(";
     if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())

Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp Sat Aug 19 04:19:16 2017
@@ -26,7 +26,8 @@ AnalysisManager::AnalysisManager(ASTCont
               Options.includeImplicitDtorsInCFG(),
               /*AddInitializers=*/true,
               Options.includeTemporaryDtorsInCFG(),
-	      Options.includeLifetimeInCFG(),
+	            Options.includeLifetimeInCFG(),
+              Options.includeLoopExitInCFG(),
               Options.shouldSynthesizeBodies(),
               Options.shouldConditionalizeStaticInitializers(),
               /*addCXXNewAllocator=*/true,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Sat Aug 19 04:19:16 2017
@@ -183,6 +183,11 @@ bool AnalyzerOptions::includeLifetimeInC
                           /* Default = */ false);
 }
 
+bool AnalyzerOptions::includeLoopExitInCFG() {
+  return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit",
+          /* Default = */ false);
+}
+
 bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
   return getBooleanOption(InlineCXXStandardLibrary,
                           "c++-stdlib-inlining",

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Sat Aug 19 04:19:16 2017
@@ -365,6 +365,7 @@ void ExprEngine::processCFGElement(const
       ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
       return;
     case CFGElement::LifetimeEnds:
+    case CFGElement::LoopExit:
       return;
   }
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/PathDiagnostic.cpp Sat Aug 19 04:19:16 2017
@@ -578,8 +578,10 @@ getLocationForCaller(const StackFrameCon
   }
   case CFGElement::TemporaryDtor:
   case CFGElement::NewAllocator:
-  case CFGElement::LifetimeEnds:
     llvm_unreachable("not yet implemented!");
+  case CFGElement::LifetimeEnds:
+  case CFGElement::LoopExit:
+    llvm_unreachable("CFGElement kind should not be on callsite!");
   }
 
   llvm_unreachable("Unknown CFGElement kind");

Modified: cfe/trunk/test/Analysis/analyzer-config.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.c?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/analyzer-config.c (original)
+++ cfe/trunk/test/Analysis/analyzer-config.c Sat Aug 19 04:19:16 2017
@@ -14,6 +14,7 @@ void foo() {
 // CHECK-NEXT: cfg-conditional-static-initializers = true
 // CHECK-NEXT: cfg-implicit-dtors = true
 // CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
 // CHECK-NEXT: cfg-temporary-dtors = false
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
@@ -30,4 +31,4 @@ void foo() {
 // CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 18
+// CHECK-NEXT: num-entries = 19

Modified: cfe/trunk/test/Analysis/analyzer-config.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.cpp?rev=311235&r1=311234&r2=311235&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/analyzer-config.cpp (original)
+++ cfe/trunk/test/Analysis/analyzer-config.cpp Sat Aug 19 04:19:16 2017
@@ -25,6 +25,7 @@ public:
 // CHECK-NEXT: cfg-conditional-static-initializers = true
 // CHECK-NEXT: cfg-implicit-dtors = true
 // CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
 // CHECK-NEXT: cfg-temporary-dtors = false
 // CHECK-NEXT: faux-bodies = true
 // CHECK-NEXT: graph-trim-interval = 1000
@@ -41,4 +42,4 @@ public:
 // CHECK-NEXT: unroll-loops = false
 // CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 23
+// CHECK-NEXT: num-entries = 24

Added: cfe/trunk/test/Analysis/loopexit-cfg-output.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/loopexit-cfg-output.cpp?rev=311235&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/loopexit-cfg-output.cpp (added)
+++ cfe/trunk/test/Analysis/loopexit-cfg-output.cpp Sat Aug 19 04:19:16 2017
@@ -0,0 +1,476 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-loopexit=true %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// CHECK:       [B6 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B3.1]++
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B4]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 12
+// CHECK-NEXT:   4: [B4.2] < [B4.3]
+// CHECK-NEXT:   T: for (...; [B4.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B5
+// CHECK-NEXT:   Succs (2): B3 B1
+
+// CHECK:       [B5]
+// CHECK-NEXT:   1: 0
+// CHECK-NEXT:   2: int i = 0;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_forloop1() {
+  for (int i = 0; i < 12; i++) {
+    i++;
+  }
+  return;
+}
+
+// CHECK:       [B4 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B3]
+// CHECK-NEXT:   T: for (; ; )
+// CHECK-NEXT:   Preds (2): B2 B4
+// CHECK-NEXT:   Succs (2): B2 NULL
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_forloop2() {
+  for (;;)
+    ;
+}
+
+// CHECK:       [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: int i;
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B4]
+// CHECK-NEXT:   1: true
+// CHECK-NEXT:   T: while [B4.1]
+// CHECK-NEXT:   Preds (2): B2 B5
+// CHECK-NEXT:   Succs (2): B3 NULL
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_while1() {
+  while (true) {
+    int i;
+  }
+}
+
+// CHECK:       [B5 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   2: 2
+// CHECK-NEXT:   3: int k = 2;
+// CHECK-NEXT:   4: return;
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: l
+// CHECK-NEXT:   2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 42
+// CHECK-NEXT:   4: [B3.2] < [B3.3]
+// CHECK-NEXT:   T: while [B3.4]
+// CHECK-NEXT:   Preds (2): B2 B4
+// CHECK-NEXT:   Succs (2): B2 B1
+
+// CHECK:       [B4]
+// CHECK-NEXT:   1: int l;
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_while2() {
+  int l;
+  while (l < 42)
+    ;
+  int k = 2;
+  return;
+}
+
+// CHECK:       [B4 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: false
+// CHECK-NEXT:   T: while [B3.1]
+// CHECK-NEXT:   Preds (2): B2 B4
+// CHECK-NEXT:   Succs (2): NULL B1
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_while3() {
+  while (false) {
+    ;
+  }
+}
+
+// CHECK:       [B4 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: DoStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B2
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   1: false
+// CHECK-NEXT:   T: do ... while [B2.1]
+// CHECK-NEXT:   Preds (2): B3 B4
+// CHECK-NEXT:   Succs (2): NULL B1
+
+// CHECK:       [B3]
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_dowhile1() {
+  do {
+  } while (false);
+}
+
+// CHECK:       [B6 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: DoStmt (LoopExit)
+// CHECK-NEXT:   2: j
+// CHECK-NEXT:   3: [B1.2]--
+// CHECK-NEXT:   4: return;
+// CHECK-NEXT:   Preds (1): B2
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B2.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 20
+// CHECK-NEXT:   4: [B2.2] < [B2.3]
+// CHECK-NEXT:   T: do ... while [B2.4]
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (2): B4 B1
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: 2
+// CHECK-NEXT:   3: [B3.1] += [B3.2]
+// CHECK-NEXT:   Preds (2): B4 B5
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B4]
+// CHECK-NEXT:   Preds (1): B2
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B5]
+// CHECK-NEXT:   1: 2
+// CHECK-NEXT:   2: int j = 2;
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B3
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_dowhile2() {
+  int j = 2;
+  do {
+    j += 2;
+  } while (j < 20);
+  j--;
+  return;
+}
+
+// CHECK:       [B10 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B9
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B8
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B4]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B4.1]++
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (1): B6
+
+// CHECK:       [B5]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B5.1]++
+// CHECK-NEXT:   Preds (1): B6
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B6]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 6
+// CHECK-NEXT:   4: [B6.2] < [B6.3]
+// CHECK-NEXT:   T: for (...; [B6.4]; ...)
+// CHECK-NEXT:   Preds (2): B4 B7
+// CHECK-NEXT:   Succs (2): B5 B3
+
+// CHECK:       [B7]
+// CHECK-NEXT:   1: 1
+// CHECK-NEXT:   2: int j = 1;
+// CHECK-NEXT:   Preds (1): B8
+// CHECK-NEXT:   Succs (1): B6
+
+// CHECK:       [B8]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B8.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B8.2] < [B8.3]
+// CHECK-NEXT:   T: while [B8.4]
+// CHECK-NEXT:   Preds (2): B2 B9
+// CHECK-NEXT:   Succs (2): B7 B1
+
+// CHECK:       [B9]
+// CHECK-NEXT:   1: 40
+// CHECK-NEXT:   2: -[B9.1]
+// CHECK-NEXT:   3: int i = -40;
+// CHECK-NEXT:   Preds (1): B10
+// CHECK-NEXT:   Succs (1): B8
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void nested_loops1() {
+  int i = -40;
+  while (i < 2) {
+    for (int j = 1; j < 6; j++)
+      i++;
+  }
+}
+
+// CHECK:       [B9 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B8
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   Preds (1): B7
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B2.1]++
+// CHECK-NEXT:   Preds (1): B3
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:       [B3]
+// CHECK-NEXT:   1: DoStmt (LoopExit)
+// CHECK-NEXT:   2: i
+// CHECK-NEXT:   3: [B3.2]--
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B2
+
+// CHECK:       [B4]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 2
+// CHECK-NEXT:   4: [B4.2] < [B4.3]
+// CHECK-NEXT:   T: do ... while [B4.4]
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (2): B6 B3
+
+// CHECK:       [B5]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B5.1]++
+// CHECK-NEXT:   Preds (2): B6 B7
+// CHECK-NEXT:   Succs (1): B4
+
+// CHECK:       [B6]
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:       [B7]
+// CHECK-NEXT:   1: j
+// CHECK-NEXT:   2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 6
+// CHECK-NEXT:   4: [B7.2] < [B7.3]
+// CHECK-NEXT:   T: for (...; [B7.4]; ...)
+// CHECK-NEXT:   Preds (2): B2 B8
+// CHECK-NEXT:   Succs (2): B5 B1
+
+// CHECK:       [B8]
+// CHECK-NEXT:   1: 40
+// CHECK-NEXT:   2: -[B8.1]
+// CHECK-NEXT:   3: int i = -40;
+// CHECK-NEXT:   4: 1
+// CHECK-NEXT:   5: int j = 1;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B7
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void nested_loops2() {
+  int i = -40;
+  for (int j = 1; j < 6; j++) {
+    do {
+      i++;
+    } while (i < 2);
+    i--;
+  }
+}
+
+// CHECK:       [B12 (ENTRY)]
+// CHECK-NEXT:   Succs (1): B11
+
+// CHECK:       [B1]
+// CHECK-NEXT:   1: WhileStmt (LoopExit)
+// CHECK-NEXT:   2: return;
+// CHECK-NEXT:   Preds (2): B3 B5
+// CHECK-NEXT:   Succs (1): B0
+
+// CHECK:       [B2]
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:       [B3]
+// CHECK-NEXT:   T: break;
+// CHECK-NEXT:   Preds (1): B4
+// CHECK-NEXT:   Succs (1): B1
+
+// CHECK:       [B4]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B4.1]++
+// CHECK-NEXT:   3: i
+// CHECK-NEXT:   4: [B4.3] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   5: 2
+// CHECK-NEXT:   6: [B4.4] % [B4.5]
+// CHECK-NEXT:   7: [B4.6] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT:   T: if [B4.7]
+// CHECK-NEXT:   Preds (1): B5
+// CHECK-NEXT:   Succs (2): B3 B2
+
+// CHECK:       [B5]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B5.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 5
+// CHECK-NEXT:   4: [B5.2] < [B5.3]
+// CHECK-NEXT:   T: while [B5.4]
+// CHECK-NEXT:   Preds (2): B2 B6
+// CHECK-NEXT:   Succs (2): B4 B1
+
+// CHECK:       [B6]
+// CHECK-NEXT:   1: ForStmt (LoopExit)
+// CHECK-NEXT:   2: 1
+// CHECK-NEXT:   3: int i = 1;
+// CHECK-NEXT:   Preds (2): B8 B10
+// CHECK-NEXT:   Succs (1): B5
+
+// CHECK:       [B7]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B7.1]++
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:       [B8]
+// CHECK-NEXT:   T: break;
+// CHECK-NEXT:   Preds (1): B9
+// CHECK-NEXT:   Succs (1): B6
+
+// CHECK:       [B9]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 4
+// CHECK-NEXT:   4: [B9.2] == [B9.3]
+// CHECK-NEXT:   T: if [B9.4]
+// CHECK-NEXT:   Preds (1): B10
+// CHECK-NEXT:   Succs (2): B8 B7
+
+// CHECK:       [B10]
+// CHECK-NEXT:   1: i
+// CHECK-NEXT:   2: [B10.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT:   3: 6
+// CHECK-NEXT:   4: [B10.2] < [B10.3]
+// CHECK-NEXT:   T: for (...; [B10.4]; ...)
+// CHECK-NEXT:   Preds (2): B7 B11
+// CHECK-NEXT:   Succs (2): B9 B6
+
+// CHECK:       [B11]
+// CHECK-NEXT:   1: 2
+// CHECK-NEXT:   2: int i = 2;
+// CHECK-NEXT:   Preds (1): B12
+// CHECK-NEXT:   Succs (1): B10
+
+// CHECK:       [B0 (EXIT)]
+// CHECK-NEXT:   Preds (1): B1
+void check_break()
+{
+  for(int i = 2; i < 6; i++) {
+    if(i == 4)
+      break;
+  }
+
+  int i = 1;
+  while(i<5){
+    i++;
+    if(i%2)
+      break;
+  }
+  
+  return;
+}




More information about the cfe-commits mailing list