Added CFG support for gotos and labels.

Modified CFG so that getEntry(), getExit(), front() and back() return
CFGBlock& instead of CFGBlock*.

llvm-svn: 41258
This commit is contained in:
Ted Kremenek 2007-08-21 23:26:17 +00:00
parent 3fc4a9f78a
commit 8a63218855
2 changed files with 93 additions and 24 deletions

View 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
@ -219,6 +237,50 @@ public:
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 ) {
// 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";

View 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