From: Ted Kremenek Date: Tue, 21 Aug 2007 23:26:17 +0000 (+0000) Subject: Added CFG support for gotos and labels. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0cebe3e29b22d11f2c65ef28fcfb5f0431877266;p=clang Added CFG support for gotos and labels. 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 --- diff --git a/AST/CFG.cpp b/AST/CFG.cpp index ba2bb3f871..98a207476c 100644 --- a/AST/CFG.cpp +++ b/AST/CFG.cpp @@ -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 #include #include @@ -56,6 +57,12 @@ class CFGBuilder : public StmtVisitor { CFGBlock* Succ; unsigned NumBlocks; + typedef llvm::DenseMap LabelMapTy; + LabelMapTy LabelMap; + + typedef std::list 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(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(S)) + OS << L->getName() << ": (LABEL)\n"; + else + (*I)->printPretty(OS); + + // Expressions need a newline. if (isa(*I)) OS << '\n'; } OS << " ------------------------\n"; @@ -287,14 +359,9 @@ void CFGBlock::print(std::ostream& OS) { break; } - case Stmt::ReturnStmtClass: { - ReturnStmt* R = cast(ControlFlowStmt); - R->printPretty(std::cerr); - break; - } - default: - assert(false && "terminator print not fully implemented"); + ControlFlowStmt->printPretty(std::cerr); + break; } } else OS << "\n"; diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h index 503930979d..0f26a8dcbf 100644 --- a/include/clang/AST/CFG.h +++ b/include/clang/AST/CFG.h @@ -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 reverse_iterator; typedef std::reverse_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