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. llvm-svn: 41554
This commit is contained in:
parent
e87935b379
commit
eda180e239
|
@ -16,6 +16,7 @@
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/StmtVisitor.h"
|
#include "clang/AST/StmtVisitor.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -58,12 +59,19 @@ class CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
|
||||||
CFGBlock* SwitchTerminatedBlock;
|
CFGBlock* SwitchTerminatedBlock;
|
||||||
unsigned NumBlocks;
|
unsigned NumBlocks;
|
||||||
|
|
||||||
|
// LabelMap records the mapping from Label expressions to their blocks.
|
||||||
typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
|
typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
|
||||||
LabelMapTy LabelMap;
|
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;
|
typedef std::vector<CFGBlock*> BackpatchBlocksTy;
|
||||||
BackpatchBlocksTy BackpatchBlocks;
|
BackpatchBlocksTy BackpatchBlocks;
|
||||||
|
|
||||||
|
// A list of labels whose address has been taken (for indirect gotos).
|
||||||
|
typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
|
||||||
|
LabelSetTy AddressTakenLabels;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
|
explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
|
||||||
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
|
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
|
||||||
|
@ -95,6 +103,7 @@ public:
|
||||||
CFGBlock* VisitBreakStmt(BreakStmt* B);
|
CFGBlock* VisitBreakStmt(BreakStmt* B);
|
||||||
CFGBlock* VisitSwitchStmt(SwitchStmt* S);
|
CFGBlock* VisitSwitchStmt(SwitchStmt* S);
|
||||||
CFGBlock* VisitSwitchCase(SwitchCase* S);
|
CFGBlock* VisitSwitchCase(SwitchCase* S);
|
||||||
|
CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CFGBlock* createBlock(bool add_successor = true);
|
CFGBlock* createBlock(bool add_successor = true);
|
||||||
|
@ -113,6 +122,7 @@ private:
|
||||||
/// CFG is transferred to the caller. If CFG construction fails, this method
|
/// CFG is transferred to the caller. If CFG construction fails, this method
|
||||||
/// returns NULL.
|
/// returns NULL.
|
||||||
CFG* CFGBuilder::buildCFG(Stmt* Statement) {
|
CFG* CFGBuilder::buildCFG(Stmt* Statement) {
|
||||||
|
assert (cfg);
|
||||||
if (!Statement) return NULL;
|
if (!Statement) return NULL;
|
||||||
|
|
||||||
// Create an empty block that will serve as the exit block for the CFG.
|
// Create an empty block that will serve as the exit block for the CFG.
|
||||||
|
@ -142,16 +152,32 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement) {
|
||||||
if (LI == LabelMap.end()) continue;
|
if (LI == LabelMap.end()) continue;
|
||||||
|
|
||||||
B->addSuccessor(LI->second);
|
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) {
|
if (B->pred_size() > 0) {
|
||||||
// create an empty entry block that has no predecessors.
|
|
||||||
Succ = B;
|
Succ = B;
|
||||||
cfg->setEntry(createBlock());
|
cfg->setEntry(createBlock());
|
||||||
}
|
}
|
||||||
else cfg->setEntry(B);
|
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* t = cfg;
|
||||||
cfg = NULL;
|
cfg = NULL;
|
||||||
return t;
|
return t;
|
||||||
|
@ -220,6 +246,14 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) {
|
||||||
}
|
}
|
||||||
else return Block;
|
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:
|
case Stmt::StmtExprClass:
|
||||||
return WalkAST_VisitStmtExpr(cast<StmtExpr>(S));
|
return WalkAST_VisitStmtExpr(cast<StmtExpr>(S));
|
||||||
|
|
||||||
|
@ -788,6 +822,25 @@ CFGBlock* CFGBuilder::VisitSwitchCase(SwitchCase* S) {
|
||||||
return CaseBlock;
|
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
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
@ -835,7 +888,13 @@ void CFG::print(std::ostream& OS) {
|
||||||
// Skip the entry block, because we already printed it.
|
// Skip the entry block, because we already printed it.
|
||||||
if (&(*I) == &getEntry() || &(*I) == &getExit()) continue;
|
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);
|
I->print(OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,10 +155,12 @@ class CFG {
|
||||||
typedef std::list<CFGBlock> CFGBlockListTy;
|
typedef std::list<CFGBlock> CFGBlockListTy;
|
||||||
CFGBlock* Entry;
|
CFGBlock* Entry;
|
||||||
CFGBlock* Exit;
|
CFGBlock* Exit;
|
||||||
|
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
|
||||||
|
// for indirect gotos
|
||||||
CFGBlockListTy Blocks;
|
CFGBlockListTy Blocks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFG() : Entry(NULL), Exit(NULL) {};
|
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL) {};
|
||||||
~CFG() {};
|
~CFG() {};
|
||||||
|
|
||||||
// Block iterators
|
// Block iterators
|
||||||
|
@ -167,21 +169,22 @@ public:
|
||||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||||
|
|
||||||
CFGBlock& front() { return Blocks.front(); }
|
CFGBlock& front() { return Blocks.front(); }
|
||||||
CFGBlock& back() { return Blocks.back(); }
|
CFGBlock& back() { return Blocks.back(); }
|
||||||
|
|
||||||
iterator begin() { return Blocks.begin(); }
|
iterator begin() { return Blocks.begin(); }
|
||||||
iterator end() { return Blocks.end(); }
|
iterator end() { return Blocks.end(); }
|
||||||
const_iterator begin() const { return Blocks.begin(); }
|
const_iterator begin() const { return Blocks.begin(); }
|
||||||
const_iterator end() const { return Blocks.end(); }
|
const_iterator end() const { return Blocks.end(); }
|
||||||
|
|
||||||
reverse_iterator rbegin() { return Blocks.rbegin(); }
|
reverse_iterator rbegin() { return Blocks.rbegin(); }
|
||||||
reverse_iterator rend() { return Blocks.rend(); }
|
reverse_iterator rend() { return Blocks.rend(); }
|
||||||
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
|
||||||
const_reverse_iterator rend() const { return Blocks.rend(); }
|
const_reverse_iterator rend() const { return Blocks.rend(); }
|
||||||
|
|
||||||
CFGBlock& getEntry() { return *Entry; }
|
CFGBlock& getEntry() { return *Entry; }
|
||||||
CFGBlock& getExit() { return *Exit; }
|
CFGBlock& getExit() { return *Exit; }
|
||||||
|
CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
|
||||||
|
|
||||||
// Utility
|
// Utility
|
||||||
|
|
||||||
|
@ -189,7 +192,8 @@ public:
|
||||||
static CFG* buildCFG(Stmt* AST);
|
static CFG* buildCFG(Stmt* AST);
|
||||||
void print(std::ostream& OS);
|
void print(std::ostream& OS);
|
||||||
void dump();
|
void dump();
|
||||||
void setEntry(CFGBlock *B) { Entry = B; }
|
void setEntry(CFGBlock *B) { Entry = B; }
|
||||||
|
void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
Loading…
Reference in New Issue