[cfe-commits] r41281 - /cfe/trunk/AST/CFG.cpp

Ted Kremenek kremenek at apple.com
Wed Aug 22 11:22:34 PDT 2007


Author: kremenek
Date: Wed Aug 22 13:22:34 2007
New Revision: 41281

URL: http://llvm.org/viewvc/llvm-project?rev=41281&view=rev
Log:
Added CFG support for: for loops

In CFG dumper, refactored the code to print block terminators into a
StmtVisitor.

Added the method "FinishBlock" to CFGBuilder to do the reversal of statements
in a block instead of calling "reverseStmts" for a block directly.  This
was necessary to fix a bug in how blocks with labels were being processed
(some cases would cause the statements to be reversed twice).  FinishBlock
detects blocks that start with labels and doesn't do a second reversal.


Modified:
    cfe/trunk/AST/CFG.cpp

Modified: cfe/trunk/AST/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/AST/CFG.cpp?rev=41281&r1=41280&r2=41281&view=diff

==============================================================================
--- cfe/trunk/AST/CFG.cpp (original)
+++ cfe/trunk/AST/CFG.cpp Wed Aug 22 13:22:34 2007
@@ -71,7 +71,7 @@
   }
   
   ~CFGBuilder() { delete cfg; }
-  
+    
   /// buildCFG - Constructs a CFG from an AST (a Stmt*).  The AST can
   ///  represent an arbitrary statement.  Examples include a single expression
   ///  or a function body (compound statement).  The ownership of the returned
@@ -88,9 +88,9 @@
     
     // Visit the statements and create the CFG.
     if (CFGBlock* B = Visit(Statement)) {
-      // Reverse the statements in the last constructed block.  Statements
-      // are inserted into the blocks in reverse order.
-      B->reverseStmts();
+      // Finalize the last constructed block.  This usually involves
+      // reversing the order of the statements in the block.
+      FinishBlock(B);
       
       // Backpatch the gotos whose label -> block mappings we didn't know
       // when we encountered them.
@@ -122,6 +122,23 @@
     if (add_successor && Succ) B->addSuccessor(Succ);
     return B;
   }
+  
+  // FinishBlock - When the last statement has been added to the block,
+  //  usually we must reverse the statements because they have been inserted
+  //  in reverse order.  When processing labels, however, there are cases
+  //  in the recursion where we may have already reversed the statements
+  //  in a block.  This method safely tidies up a block: if the block
+  //  has a label at the front, it has already been reversed.  Otherwise,
+  //  we reverse it.
+  void FinishBlock(CFGBlock* B) {
+    assert (B);
+    CFGBlock::iterator I = B->begin();
+    if (I != B->end()) {
+      Stmt* S = *I;
+      if (S->getStmtClass() != Stmt::LabelStmtClass)
+        B->reverseStmts();
+    }
+  }
 
   /// Here we handle statements with no branching control flow.
   CFGBlock* VisitStmt(Stmt* Statement) {
@@ -138,15 +155,22 @@
     return Block;
   }
   
+  CFGBlock* VisitNullStmt(NullStmt* Statement) {
+    return Block;
+  }
+  
   CFGBlock* VisitCompoundStmt(CompoundStmt* C) {
     //   The value returned from this function is the last created CFGBlock
     //   that represents the "entry" point for the translated AST node.
+    CFGBlock* LastBlock;
+    
     for (CompoundStmt::reverse_body_iterator I = C->body_rbegin(),
-          E = C->body_rend(); I != E; ++I )
+         E = C->body_rend(); I != E; ++I )
       // Add the statement to the current block.
-      if (!Visit(*I)) return NULL;
+      if (!(LastBlock=Visit(*I)))
+        return NULL;
 
-    return Block;
+    return LastBlock;
   }
   
   CFGBlock* VisitIfStmt(IfStmt* I) {
@@ -163,7 +187,7 @@
     // successor block.
     if (Block) { 
       Succ = Block;
-      Block->reverseStmts();
+      FinishBlock(Block);
     }
     
     // Process the false branch.  NULL out Block so that the recursive
@@ -179,7 +203,7 @@
       Block = NULL;
       ElseBlock = Visit(Else);          
       if (!ElseBlock) return NULL;
-      ElseBlock->reverseStmts();        
+      FinishBlock(ElseBlock);
     }
     
     // Process the true branch.  NULL out Block so that the recursive
@@ -193,7 +217,7 @@
       Block = NULL;        
       ThenBlock = Visit(Then);        
       if (!ThenBlock) return NULL;
-      ThenBlock->reverseStmts();
+      FinishBlock(ThenBlock);
     }
 
     // Now create a new block containing the if statement.        
@@ -221,7 +245,7 @@
     //       keep a basic block for that code; a simple "mark-and-sweep"
     //       from the entry block will be able to report such dead
     //       blocks.
-    if (Block) Block->reverseStmts();        
+    if (Block) FinishBlock(Block);
 
     // Create the new block.
     Block = createBlock(false);
@@ -241,16 +265,15 @@
   CFGBlock* VisitLabelStmt(LabelStmt* L) {
     // Get the block of the labeled statement.  Add it to our map.
     CFGBlock* LabelBlock = Visit(L->getSubStmt());
-    
+    assert (LabelBlock);    
 
     assert (LabelMap.find(L) == LabelMap.end() && "label already in map");
     LabelMap[ L ] = LabelBlock;
     
     // Labels partition blocks, so this is the end of the basic block
     // we were processing (the label is the first statement).    
-    assert (Block);
-    Block->appendStmt(L);
-    Block->reverseStmts();
+    LabelBlock->appendStmt(L);
+    FinishBlock(LabelBlock);
     
     // We set Block to NULL to allow lazy creation of a new block
     // (if necessary);
@@ -265,7 +288,7 @@
   CFGBlock* VisitGotoStmt(GotoStmt* G) {
     // Goto is a control-flow statement.  Thus we stop processing the
     // current block and create a new one.
-    if (Block) Block->reverseStmts();
+    if (Block) FinishBlock(Block);
     Block = createBlock(false);
     Block->setTerminator(G);
     
@@ -281,6 +304,59 @@
 
     return Block;            
   }
+  
+  CFGBlock* VisitForStmt(ForStmt* F) {
+    // For is a control-flow statement.  Thus we stop processing the
+    // current block.
+    if (Block) FinishBlock(Block);
+    
+    // Besides the loop body, we actually create two new blocks:
+    //
+    // The first contains the initialization statement for the loop.
+    //
+    // The second block evaluates the loop condition.
+    //
+    // We create the initialization block last, as that will be the block
+    // we return for the recursion.
+    
+    CFGBlock* CondBlock = createBlock(false);
+    if (Stmt* C = F->getCond()) CondBlock->appendStmt(C);
+    CondBlock->setTerminator(F);
+    Succ = CondBlock;
+    
+    // Now create the loop body.
+    {
+      assert (F->getBody());
+      SaveAndRestore<CFGBlock*> sv(Block);
+      
+      // create a new block to contain the body.      
+      Block = createBlock();
+      
+      // If we have increment code, insert it at the end of the body block.
+      if (Stmt* I = F->getInc()) Block->appendStmt(I);
+      
+      // Now populate the body block, and in the process create new blocks
+      // as we walk the body of the loop.
+      CFGBlock* BodyBlock = Visit(F->getBody());
+      
+      assert (BodyBlock);      
+      FinishBlock(BodyBlock);
+      
+      // This new body block is a successor to our condition block.
+      CondBlock->addSuccessor(BodyBlock);
+    }
+
+    // Link up the condition block with the code that follows the loop.
+    // (the false branch).
+    CondBlock->addSuccessor(Block);
+
+    // Now create the block to contain the initialization.
+    Succ = CondBlock;    
+    Block = createBlock();
+    
+    if (Stmt* I = F->getInit()) Block->appendStmt(I);
+    return Block;    
+  }
 };
 
 // BuildCFG - A helper function that builds CFGs from ASTS.
@@ -310,6 +386,36 @@
   OS << "\n";
 }
 
+
+namespace {
+
+  class CFGBlockTerminatorPrint : public StmtVisitor<CFGBlockTerminatorPrint,
+                                                     void > {
+    std::ostream& OS;
+  public:
+    CFGBlockTerminatorPrint(std::ostream& os) : OS(os) {}
+    
+    void VisitIfStmt(IfStmt* I) {
+      OS << "if ";
+      I->getCond()->printPretty(std::cerr);
+      OS << "\n";
+    }
+    
+    // Default case.
+    void VisitStmt(Stmt* S) { S->printPretty(OS); }
+    
+    void VisitForStmt(ForStmt* F) {
+      OS << "for (" ;
+      if (Stmt* I = F->getInit()) I->printPretty(OS);
+      OS << " ; ";
+      if (Stmt* C = F->getCond()) C->printPretty(OS);
+      OS << " ; ";
+      if (Stmt* I = F->getInc()) I->printPretty(OS);
+      OS << ")\n";                                                       
+    }        
+  };
+}
+
 // dump - A simply pretty printer of a CFGBlock that outputs to stderr.
 void CFGBlock::dump() { print(std::cerr); }
 
@@ -349,22 +455,10 @@
   
   // Print the terminator of this block.
   OS << "\n    Terminator: ";
-  if (ControlFlowStmt) {
-    switch (ControlFlowStmt->getStmtClass()) {
-      case Stmt::IfStmtClass: {
-        IfStmt* I = cast<IfStmt>(ControlFlowStmt);
-        OS << "if ";
-        I->getCond()->printPretty(std::cerr);
-        OS << "\n";
-        break;
-      }
-      
-      default:
-        ControlFlowStmt->printPretty(std::cerr);
-        break;
-    }
-  }
-  else OS << "<NULL>\n";
+  if (ControlFlowStmt)
+    CFGBlockTerminatorPrint(OS).Visit(ControlFlowStmt);
+  else
+    OS << "<NULL>\n";
 
   // Print the successors of this block.
   OS << "    Successors (" << succ_size() << "):";





More information about the cfe-commits mailing list