]> granicus.if.org Git - clang/commitdiff
Added CFG support for gotos and labels.
authorTed Kremenek <kremenek@apple.com>
Tue, 21 Aug 2007 23:26:17 +0000 (23:26 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 21 Aug 2007 23:26:17 +0000 (23:26 +0000)
Modified CFG so that getEntry(), getExit(), front() and back() return
CFGBlock& instead of CFGBlock*.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41258 91177308-0d34-0410-b5e6-96231b3b80d8

AST/CFG.cpp
include/clang/AST/CFG.h

index ba2bb3f87156526bb53d5b2e0e488dfe4b86c219..98a207476cddbcbff844e5fcfcce2151685b4089 100644 (file)
@@ -15,6 +15,7 @@
 #include "clang/AST/CFG.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/DenseMap.h"
 #include <iostream>
 #include <iomanip>
 #include <algorithm>
@@ -56,6 +57,12 @@ class CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
   CFGBlock* Succ;
   unsigned NumBlocks;
   
+  typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
+  LabelMapTy LabelMap;
+  
+  typedef std::list<CFGBlock*> BackpatchBlocksTy;
+  BackpatchBlocksTy BackpatchBlocks;
+  
 public:  
   explicit CFGBuilder() : cfg(NULL), Block(NULL), Exit(NULL), Succ(NULL), 
                           NumBlocks(0) {
@@ -73,7 +80,7 @@ public:
   CFG* buildCFG(Stmt* Statement) {
     if (!Statement) return NULL;
   
-    assert (cfg && "CFGBuilder should only be used to construct one CFG");
+    assert (!Exit && "CFGBuilder should only be used to construct one CFG");
 
     // Create the exit block.
     Block = createBlock();
@@ -84,17 +91,28 @@ public:
       // Reverse the statements in the last constructed block.  Statements
       // are inserted into the blocks in reverse order.
       B->reverseStmts();
+      
+      // Backpatch the gotos whose label -> block mappings we didn't know
+      // when we encountered them.
+      for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), 
+           E = BackpatchBlocks.end(); I != E; ++I ) {
+       
+        CFGBlock* B = *I;
+        GotoStmt* G = cast<GotoStmt>(B->getTerminator());
+        LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
+
+        if (LI == LabelMap.end())
+          return NULL; // No matching label.  Bad CFG.
+        
+        B->addSuccessor(LI->second);                   
+      }        
+      
       // NULL out cfg so that repeated calls
       CFG* t = cfg;
       cfg = NULL;
       return t;
     }
-    else {
-      // Error occured while building CFG: Delete the partially constructed CFG.
-      delete cfg;
-      cfg = NULL;
-      return NULL;
-    }
+    else return NULL;
   }
   
   // createBlock - Used to lazily create blocks that are connected
@@ -218,7 +236,51 @@ public:
     if (R->getRetValue()) Block->appendStmt(R->getRetValue());
     
     return Block;
-  }  
+  }
+  
+  CFGBlock* VisitLabelStmt(LabelStmt* L) {
+    // Get the block of the labeled statement.  Add it to our map.
+    CFGBlock* LabelBlock = Visit(L->getSubStmt());
+    
+
+    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();
+    
+    // We set Block to NULL to allow lazy creation of a new block
+    // (if necessary);
+    Block = NULL;
+    
+    // This block is now the implicit successor of other blocks.
+    Succ = LabelBlock;
+    
+    return LabelBlock;
+  }
+  
+  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();
+    Block = createBlock(false);
+    Block->setTerminator(G);
+    
+    // If we already know the mapping to the label block add the
+    // successor now.
+    LabelMapTy::iterator I = LabelMap.find(G->getLabel());
+    
+    if (I == LabelMap.end())
+      // We will need to backpatch this block later.
+      BackpatchBlocks.push_back(Block);
+    else
+      Block->addSuccessor(I->second);
+
+    return Block;            
+  }
 };
 
 // BuildCFG - A helper function that builds CFGs from ASTS.
@@ -240,8 +302,8 @@ void CFG::print(std::ostream& OS) {
   // designate the Entry and Exit blocks.
   for (iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
     OS << "\n  [ B" << I->getBlockID();
-    if (&(*I) == getExit()) OS << " (EXIT) ]\n";
-    else if (&(*I) == getEntry()) OS << " (ENTRY) ]\n";
+    if (&(*I) == &getExit()) OS << " (EXIT) ]\n";
+    else if (&(*I) == &getEntry()) OS << " (ENTRY) ]\n";
     else OS << " ]\n";
     I->print(OS);
   }
@@ -259,8 +321,18 @@ void CFGBlock::print(std::ostream& OS) {
   OS << "    ------------------------\n";
   unsigned j = 1;
   for (iterator I = Stmts.begin(), E = Stmts.end() ; I != E ; ++I, ++j ) {
-    OS << "    " << std::setw(3) << j << ": ";
-    (*I)->printPretty(OS);
+    // Print the statement # in the basic block.
+    OS << "    " << std::setw(3) << j << ": ";    
+
+    // Print the statement/expression.
+    Stmt* S = *I;
+    
+    if (LabelStmt* L = dyn_cast<LabelStmt>(S))
+      OS << L->getName() << ": (LABEL)\n";
+    else
+      (*I)->printPretty(OS);
+      
+    // Expressions need a newline.
     if (isa<Expr>(*I)) OS << '\n';
   }
   OS << "    ------------------------\n";
@@ -287,14 +359,9 @@ void CFGBlock::print(std::ostream& OS) {
         break;
       }
       
-      case Stmt::ReturnStmtClass: {
-        ReturnStmt* R = cast<ReturnStmt>(ControlFlowStmt);
-        R->printPretty(std::cerr);
-        break;
-      }
-      
       default:
-        assert(false && "terminator print not fully implemented");
+        ControlFlowStmt->printPretty(std::cerr);
+        break;
     }
   }
   else OS << "<NULL>\n";
index 503930979d76dd6fe4d5052ce80a8ccb79af022b..0f26a8dcbf59a0a15b5c9c921ccb3a27d7c8d64d 100644 (file)
@@ -128,6 +128,8 @@ public:
   
   void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); }
   void setTerminator(Stmt* Statement) { ControlFlowStmt = Statement; }
+  Stmt* getTerminator() { return ControlFlowStmt; }
+  
   void reverseStmts();
   
   void addSuccessor(CFGBlock* Block) {
@@ -160,7 +162,7 @@ public:
   
   CFGBlock* createBlock(unsigned blockID) { 
     Blocks.push_front(CFGBlock(blockID));
-    return front();
+    return &front();
   }
   
   // Block iterators
@@ -169,8 +171,8 @@ public:
   typedef std::reverse_iterator<iterator>                     reverse_iterator;
   typedef std::reverse_iterator<const_iterator>         const_reverse_iterator;
 
-  CFGBlock*                    front()             { return &Blocks.front();  }
-  CFGBlock*                    back()              { return &Blocks.back();   }
+  CFGBlock&                    front()             { return Blocks.front();  }
+  CFGBlock&                    back()              { return Blocks.back();   }
   
   iterator                     begin()             { return Blocks.begin();   }
   iterator                     end()               { return Blocks.end();     }
@@ -182,8 +184,8 @@ public:
   const_reverse_iterator       rbegin()      const { return Blocks.rbegin();  }
   const_reverse_iterator       rend()        const { return Blocks.rend();    }
   
-  CFGBlock*                    getEntry()          { return front();          }
-  CFGBlock*                    getExit()           { return back();           }
+  CFGBlock&                    getEntry()          { return front();          }
+  CFGBlock&                    getExit()           { return back();           }
   
   // Utility