[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