[cfe-commits] r41554 - in /cfe/trunk: AST/CFG.cpp include/clang/AST/CFG.h

Ted Kremenek kremenek at apple.com
Tue Aug 28 12:26:49 PDT 2007


Author: kremenek
Date: Tue Aug 28 14:26:49 2007
New Revision: 41554

URL: http://llvm.org/viewvc/llvm-project?rev=41554&view=rev
Log:
Added support for indirect-gotos (GCC extension) in source-level CFGs.
This involves the construction of a specialized "dispatch" block that
all basic blocks containing indirect gotos unconditionally transfer
control-flow to.  The successors of the dispatch block has as its successors
all of the blocks containing labels whose address was taken somewhere in
the function.

Modified:
    cfe/trunk/AST/CFG.cpp
    cfe/trunk/include/clang/AST/CFG.h

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

==============================================================================
--- cfe/trunk/AST/CFG.cpp (original)
+++ cfe/trunk/AST/CFG.cpp Tue Aug 28 14:26:49 2007
@@ -16,6 +16,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/StmtVisitor.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include <iostream>
 #include <iomanip>
 #include <algorithm>
@@ -58,12 +59,19 @@
   CFGBlock* SwitchTerminatedBlock;
   unsigned NumBlocks;
   
+  // LabelMap records the mapping from Label expressions to their blocks.
   typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
   LabelMapTy LabelMap;
   
+  // A list of blocks that end with a "goto" that must be backpatched to
+  // their resolved targets upon completion of CFG construction.
   typedef std::vector<CFGBlock*> BackpatchBlocksTy;
   BackpatchBlocksTy BackpatchBlocks;
   
+  // A list of labels whose address has been taken (for indirect gotos).
+  typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
+  LabelSetTy AddressTakenLabels;
+  
 public:  
   explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
                           ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
@@ -95,6 +103,7 @@
   CFGBlock* VisitBreakStmt(BreakStmt* B);
   CFGBlock* VisitSwitchStmt(SwitchStmt* S);
   CFGBlock* VisitSwitchCase(SwitchCase* S);
+  CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
   
 private:
   CFGBlock* createBlock(bool add_successor = true);
@@ -113,6 +122,7 @@
 ///  CFG is transferred to the caller.  If CFG construction fails, this method
 ///  returns NULL.
 CFG* CFGBuilder::buildCFG(Stmt* Statement) {
+  assert (cfg);
   if (!Statement) return NULL;
 
   // Create an empty block that will serve as the exit block for the CFG.
@@ -142,16 +152,32 @@
       if (LI == LabelMap.end()) continue;
       
       B->addSuccessor(LI->second);                   
-    }                          
+    }
     
+    // Add successors to the Indirect Goto Dispatch block (if we have one).
+    if (CFGBlock* B = cfg->getIndirectGotoBlock())
+      for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
+           E = AddressTakenLabels.end(); I != E; ++I ) {
+
+        // Lookup the target block.
+        LabelMapTy::iterator LI = LabelMap.find(*I);
+
+        // If there is no target block that contains label, then we are looking
+        // at an incomplete AST.  Handle this by not registering a successor.
+        if (LI == LabelMap.end()) continue;
+        
+        B->addSuccessor(LI->second);           
+      }
+                                                        
+    // Create an empty entry block that has no predecessors.    
     if (B->pred_size() > 0) {
-      // create an empty entry block that has no predecessors.
       Succ = B;
       cfg->setEntry(createBlock());
     }
     else cfg->setEntry(B);
     
-    // NULL out cfg so that repeated calls
+    // NULL out cfg so that repeated calls to the builder will fail and that
+    // the ownership of the constructed CFG is passed to the caller.
     CFG* t = cfg;
     cfg = NULL;
     return t;
@@ -220,6 +246,14 @@
       }
       else return Block;
       
+    case Stmt::AddrLabelExprClass: {
+      AddrLabelExpr* A = cast<AddrLabelExpr>(S);
+      AddressTakenLabels.insert(A->getLabel());
+      
+      if (AlwaysAddStmt) Block->appendStmt(S);
+      return Block;
+    }
+      
     case Stmt::StmtExprClass:
       return WalkAST_VisitStmtExpr(cast<StmtExpr>(S));
 
@@ -788,6 +822,25 @@
   return CaseBlock;    
 }
 
+CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
+  // Lazily create the indirect-goto dispatch block if there isn't one
+  // already.
+  CFGBlock* IBlock = cfg->getIndirectGotoBlock();
+  
+  if (!IBlock) {
+    IBlock = createBlock(false);
+    cfg->setIndirectGotoBlock(IBlock);
+  }
+  
+  // IndirectGoto is a control-flow statement.  Thus we stop processing the
+  // current block and create a new one.
+  if (Block) FinishBlock(Block);
+  Block = createBlock(false);
+  Block->setTerminator(I);
+  Block->addSuccessor(IBlock);
+  return addStmt(I->getTarget());
+}
+
 
 } // end anonymous namespace
 
@@ -835,7 +888,13 @@
     // Skip the entry block, because we already printed it.
     if (&(*I) == &getEntry() || &(*I) == &getExit()) continue;
       
-    OS << "\n  [ B" << I->getBlockID() << " ]\n";    
+    OS << "\n  [ B" << I->getBlockID();
+
+    if (&(*I) == getIndirectGotoBlock())
+      OS << " (INDIRECT GOTO DISPATCH) ]\n";
+    else
+      OS << " ]\n";
+      
     I->print(OS);
   }
 

Modified: cfe/trunk/include/clang/AST/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CFG.h?rev=41554&r1=41553&r2=41554&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/CFG.h (original)
+++ cfe/trunk/include/clang/AST/CFG.h Tue Aug 28 14:26:49 2007
@@ -155,10 +155,12 @@
   typedef std::list<CFGBlock> CFGBlockListTy;
   CFGBlock* Entry;
   CFGBlock* Exit;
+  CFGBlock* IndirectGotoBlock;  // Special block to contain collective dispatch
+                                // for indirect gotos
   CFGBlockListTy Blocks;
   
 public:
-  CFG() : Entry(NULL), Exit(NULL) {};
+  CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL) {};
   ~CFG() {};
   
   // Block iterators
@@ -167,21 +169,22 @@
   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();      }
-  const_iterator               begin()       const { return Blocks.begin();    }
-  const_iterator               end()         const { return Blocks.end();      } 
-  
-  reverse_iterator             rbegin()            { return Blocks.rbegin();   }
-  reverse_iterator             rend()              { return Blocks.rend();     }
-  const_reverse_iterator       rbegin()      const { return Blocks.rbegin();   }
-  const_reverse_iterator       rend()        const { return Blocks.rend();     }
-  
-  CFGBlock&                    getEntry()          { return *Entry;            }
-  CFGBlock&                    getExit()           { return *Exit;             }
+  iterator                  begin()                { return Blocks.begin(); }
+  iterator                  end()                  { return Blocks.end(); }
+  const_iterator            begin()       const    { return Blocks.begin(); }
+  const_iterator            end()         const    { return Blocks.end(); } 
+  
+  reverse_iterator          rbegin()               { return Blocks.rbegin(); }
+  reverse_iterator          rend()                 { return Blocks.rend(); }
+  const_reverse_iterator    rbegin()      const    { return Blocks.rbegin(); }
+  const_reverse_iterator    rend()        const    { return Blocks.rend(); }
+  
+  CFGBlock&                 getEntry()             { return *Entry; }
+  CFGBlock&                 getExit()              { return *Exit; }
+  CFGBlock*                 getIndirectGotoBlock() { return IndirectGotoBlock; }
   
   // Utility
   
@@ -189,7 +192,8 @@
   static CFG* buildCFG(Stmt* AST);
   void print(std::ostream& OS);
   void dump();
-  void setEntry(CFGBlock *B) { Entry = B; }      
+  void setEntry(CFGBlock *B) { Entry = B; }
+  void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }   
 };
 
 } // end namespace clang





More information about the cfe-commits mailing list