Index: include/clang/Analysis/CFG.h =================================================================== --- include/clang/Analysis/CFG.h +++ include/clang/Analysis/CFG.h @@ -59,6 +59,7 @@ Initializer, NewAllocator, LifetimeEnds, + LoopEntrance, LoopExit, // dtor kind AutomaticObjectDtor, @@ -175,6 +176,22 @@ /// /// Note: a loop exit element can be reached even when the loop body was never /// entered. +class CFGLoopEntrance : public CFGElement { +public: + explicit CFGLoopEntrance(const Stmt *stmt) : CFGElement(LoopEntrance, stmt) {} + + const Stmt *getLoopStmt() const { + return static_cast(Data1.getPointer()); + } + +private: + friend class CFGElement; + CFGLoopEntrance() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == LoopEntrance; + } +}; + class CFGLoopExit : public CFGElement { public: explicit CFGLoopExit(const Stmt *stmt) @@ -756,6 +773,10 @@ Elements.push_back(CFGLoopExit(LoopStmt), C); } + void appendLoopEntrance(const Stmt *LoopStmt, BumpVectorContext &C) { + Elements.push_back(CFGLoopEntrance(LoopStmt), C); + } + void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { Elements.push_back(CFGDeleteDtor(RD, DE), C); } Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -610,6 +610,7 @@ } CFGBlock *addInitializer(CXXCtorInitializer *I); void addLoopExit(const Stmt *LoopStmt); + void addLoopEntrance(const Stmt *LoopStmt); void addAutomaticObjDtors(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt *S); void addLifetimeEnds(LocalScope::const_iterator B, @@ -664,6 +665,10 @@ B->appendLoopExit(LoopStmt, cfg->getBumpVectorContext()); } + void appendLoopEntrance(CFGBlock *B, const Stmt *LoopStmt) { + B->appendLoopEntrance(LoopStmt, cfg->getBumpVectorContext()); + } + void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) { B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext()); } @@ -1275,6 +1280,13 @@ appendLoopExit(Block, LoopStmt); } +void CFGBuilder::addLoopEntrance(const Stmt *LoopStmt) { + if (!BuildOpts.AddLoopExit) + return; + autoCreateBlock(); + appendLoopEntrance(Block, LoopStmt); +} + void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt *S) { @@ -2820,14 +2832,15 @@ // Link up the loop-back block to the entry condition block. addSuccessor(TransitionBlock, EntryConditionBlock); - - // The condition block is the implicit successor for any code above the loop. + + // The condition block is the implicit sucacessor for any code above the loop. Succ = EntryConditionBlock; // If the loop contains initialization, create a new block for those // statements. This block can also contain statements that precede the loop. if (Stmt *I = F->getInit()) { Block = createBlock(); + addLoopEntrance(F); return addStmt(I); } @@ -2835,7 +2848,8 @@ // NULL out Block to force lazy block construction. Block = nullptr; Succ = EntryConditionBlock; - return EntryConditionBlock; + addLoopEntrance(F); + return (Block ? Block : Succ); } CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { @@ -3141,7 +3155,8 @@ // Return the condition block, which is the dominating block for the loop. Succ = EntryConditionBlock; - return EntryConditionBlock; + addLoopEntrance(W); + return (Block ? Block : Succ); } @@ -3291,7 +3306,8 @@ // Return the loop body, which is the dominating block for the loop. Succ = BodyBlock; - return BodyBlock; + addLoopEntrance(D); + return (Block ? Block : Succ); } CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) { @@ -4176,6 +4192,7 @@ case CFGElement::Initializer: case CFGElement::NewAllocator: case CFGElement::LoopExit: + case CFGElement::LoopEntrance: case CFGElement::LifetimeEnds: llvm_unreachable("getDestructorDecl should only be used with " "ImplicitDtors"); @@ -4597,6 +4614,9 @@ OS << " (Lifetime ends)\n"; + } else if (Optional LE = E.getAs()) { + const Stmt *LoopStmt = LE->getLoopStmt(); + OS << LoopStmt->getStmtClassName() << " (LoopEntrance)\n"; } else if (Optional LE = E.getAs()) { const Stmt *LoopStmt = LE->getLoopStmt(); OS << LoopStmt->getStmtClassName() << " (LoopExit)\n"; Index: test/Analysis/loopexit-cfg-output.cpp =================================================================== --- test/Analysis/loopexit-cfg-output.cpp +++ test/Analysis/loopexit-cfg-output.cpp @@ -34,6 +34,7 @@ // CHECK: [B5] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: int i = 0; +// CHECK-NEXT: 3: ForStmt (LoopEntrance) // CHECK-NEXT: Preds (1): B6 // CHECK-NEXT: Succs (1): B4 @@ -46,8 +47,8 @@ return; } -// CHECK: [B4 (ENTRY)] -// CHECK-NEXT: Succs (1): B3 +// CHECK: [B5 (ENTRY)] +// CHECK-NEXT: Succs (1): B4 // CHECK: [B1] // CHECK-NEXT: 1: ForStmt (LoopExit) @@ -62,6 +63,11 @@ // CHECK-NEXT: Preds (2): B2 B4 // CHECK-NEXT: Succs (2): B2 NULL +// CHECK: [B4] +// CHECK-NEXT: 1: ForStmt (LoopEntrance) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B3 + // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void check_forloop2() { @@ -69,8 +75,8 @@ ; } -// CHECK: [B5 (ENTRY)] -// CHECK-NEXT: Succs (1): B4 +// CHECK: [B6 (ENTRY)] +// CHECK-NEXT: Succs (1): B5 // CHECK: [B1] // CHECK-NEXT: 1: WhileStmt (LoopExit) @@ -91,6 +97,11 @@ // CHECK-NEXT: Preds (2): B2 B5 // CHECK-NEXT: Succs (2): B3 NULL +// CHECK: [B5] +// CHECK-NEXT: 1: WhileStmt (LoopEntrance) +// CHECK-NEXT: Preds (1): B6 +// CHECK-NEXT: Succs (1): B4 + // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void check_while1() { @@ -125,6 +136,7 @@ // CHECK: [B4] // CHECK-NEXT: 1: int l; +// CHECK-NEXT: 2: WhileStmt (LoopEntrance) // CHECK-NEXT: Preds (1): B5 // CHECK-NEXT: Succs (1): B3 @@ -138,8 +150,8 @@ return; } -// CHECK: [B4 (ENTRY)] -// CHECK-NEXT: Succs (1): B3 +// CHECK: [B5 (ENTRY)] +// CHECK-NEXT: Succs (1): B4 // CHECK: [B1] // CHECK-NEXT: 1: WhileStmt (LoopExit) @@ -155,6 +167,11 @@ // CHECK-NEXT: Preds (2): B2 B4 // CHECK-NEXT: Succs (2): NULL B1 +// CHECK: [B4] +// CHECK-NEXT: 1: WhileStmt (LoopEntrance) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B3 + // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void check_while3() { @@ -163,8 +180,8 @@ } } -// CHECK: [B4 (ENTRY)] -// CHECK-NEXT: Succs (1): B2 +// CHECK: [B5 (ENTRY)] +// CHECK-NEXT: Succs (1): B4 // CHECK: [B1] // CHECK-NEXT: 1: DoStmt (LoopExit) @@ -180,6 +197,11 @@ // CHECK: [B3] // CHECK-NEXT: Succs (1): B2 +// CHECK: [B4] +// CHECK-NEXT: 1: DoStmt (LoopEntrance) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B2 + // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 void check_dowhile1() { @@ -221,6 +243,7 @@ // CHECK: [B5] // CHECK-NEXT: 1: 2 // CHECK-NEXT: 2: int j = 2; +// CHECK-NEXT: 3: DoStmt (LoopEntrance) // CHECK-NEXT: Preds (1): B6 // CHECK-NEXT: Succs (1): B3 @@ -276,6 +299,7 @@ // CHECK: [B7] // CHECK-NEXT: 1: 1 // CHECK-NEXT: 2: int j = 1; +// CHECK-NEXT: 3: ForStmt (LoopEntrance) // CHECK-NEXT: Preds (1): B8 // CHECK-NEXT: Succs (1): B6 @@ -292,6 +316,7 @@ // CHECK-NEXT: 1: 40 // CHECK-NEXT: 2: -[B9.1] // CHECK-NEXT: 3: int i = -40; +// CHECK-NEXT: 4: WhileStmt (LoopEntrance) // CHECK-NEXT: Preds (1): B10 // CHECK-NEXT: Succs (1): B8 @@ -305,19 +330,19 @@ } } -// CHECK: [B9 (ENTRY)] -// CHECK-NEXT: Succs (1): B8 +// CHECK: [B10 (ENTRY)] +// CHECK-NEXT: Succs (1): B9 // CHECK: [B1] // CHECK-NEXT: 1: ForStmt (LoopExit) -// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Preds (1): B8 // 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-NEXT: Succs (1): B8 // CHECK: [B3] // CHECK-NEXT: 1: DoStmt (LoopExit) @@ -346,22 +371,28 @@ // CHECK-NEXT: Succs (1): B5 // CHECK: [B7] +// CHECK-NEXT: 1: DoStmt (LoopEntrance) +// CHECK-NEXT: Preds (1): B8 +// CHECK-NEXT: Succs (1): B5 + +// CHECK: [B8] // CHECK-NEXT: 1: j -// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, int) +// CHECK-NEXT: 2: [B8.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-NEXT: 4: [B8.2] < [B8.3] +// CHECK-NEXT: T: for (...; [B8.4]; ...) +// CHECK-NEXT: Preds (2): B2 B9 +// CHECK-NEXT: Succs (2): B7 B1 -// CHECK: [B8] +// CHECK: [B9] // CHECK-NEXT: 1: 40 -// CHECK-NEXT: 2: -[B8.1] +// CHECK-NEXT: 2: -[B9.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-NEXT: 6: ForStmt (LoopEntrance) +// CHECK-NEXT: Preds (1): B10 +// CHECK-NEXT: Succs (1): B8 // CHECK: [B0 (EXIT)] // CHECK-NEXT: Preds (1): B1 @@ -418,6 +449,7 @@ // CHECK-NEXT: 1: ForStmt (LoopExit) // CHECK-NEXT: 2: 1 // CHECK-NEXT: 3: int i = 1; +// CHECK-NEXT: 4: WhileStmt (LoopEntrance) // CHECK-NEXT: Preds (2): B8 B10 // CHECK-NEXT: Succs (1): B5 @@ -453,24 +485,24 @@ // CHECK: [B11] // CHECK-NEXT: 1: 2 // CHECK-NEXT: 2: int i = 2; +// CHECK-NEXT: 3: ForStmt (LoopEntrance) // 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) +void check_break() { + for (int i = 2; i < 6; i++) { + if (i == 4) break; } int i = 1; - while(i<5){ + while (i < 5) { i++; - if(i%2) + if (i % 2) break; } - + return; }