#include "llvm/ADT/GraphTraits.h"
#include "llvm/Support/Allocator.h"
-#include <list>
-#include <vector>
+#include "clang/Analysis/Support/BumpVector.h"
#include <cassert>
namespace llvm {
///
class CFGBlock {
class StatementList {
- typedef std::vector<Stmt*> ImplTy;
+ typedef BumpVector<Stmt*> ImplTy;
ImplTy Impl;
public:
+ StatementList(BumpVectorContext &C) : Impl(C, 4) {}
+
typedef std::reverse_iterator<ImplTy::iterator> iterator;
typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator;
typedef ImplTy::iterator reverse_iterator;
typedef ImplTy::const_iterator const_reverse_iterator;
- void push_back(Stmt *s) { Impl.push_back(s); }
+ void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); }
Stmt *front() const { return Impl.back(); }
Stmt *back() const { return Impl.front(); }
/// Predecessors/Successors - Keep track of the predecessor / successor
/// CFG blocks.
- typedef std::vector<CFGBlock*> AdjacentBlocks;
+ typedef BumpVector<CFGBlock*> AdjacentBlocks;
AdjacentBlocks Preds;
AdjacentBlocks Succs;
public:
- explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL),
- LoopTarget(NULL), BlockID(blockid) {}
+ explicit CFGBlock(unsigned blockid, BumpVectorContext &C)
+ : Stmts(C), Label(NULL), Terminator(NULL), LoopTarget(NULL),
+ BlockID(blockid), Preds(C, 1), Succs(C, 1) {}
~CFGBlock() {};
// Statement iterators
// Manipulation of block contents
- void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); }
void setTerminator(Stmt* Statement) { Terminator = Statement; }
void setLabel(Stmt* Statement) { Label = Statement; }
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
void reverseStmts();
- void addSuccessor(CFGBlock* Block) {
- if (Block)
- Block->Preds.push_back(this);
- Succs.push_back(Block);
- }
-
unsigned getBlockID() const { return BlockID; }
void dump(const CFG *cfg, const LangOptions &LO) const;
void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const;
+
+ void addSuccessor(CFGBlock* Block, BumpVectorContext &C) {
+ if (Block)
+ Block->Preds.push_back(this, C);
+ Succs.push_back(Block, C);
+ }
+
+ void appendStmt(Stmt* Statement, BumpVectorContext &C) {
+ Stmts.push_back(Statement, C);
+ }
};
// Block Iterators
//===--------------------------------------------------------------------===//
- typedef std::list<CFGBlock> CFGBlockListTy;
-
+ typedef BumpVector<CFGBlock*> CFGBlockListTy;
typedef CFGBlockListTy::iterator iterator;
typedef CFGBlockListTy::const_iterator const_iterator;
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(); }
template <typename CALLBACK>
void VisitBlockStmts(CALLBACK& O) const {
for (const_iterator I=begin(), E=end(); I != E; ++I)
- for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI != BE; ++BI)
+ for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
+ BI != BE; ++BI)
O(*BI);
}
//===--------------------------------------------------------------------===//
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
- BlkExprMap(NULL) {};
+ BlkExprMap(NULL), Blocks(BlkBVC, 10) {};
~CFG();
llvm::BumpPtrAllocator& getAllocator() {
- return Alloc;
+ return BlkBVC.getAllocator();
+ }
+
+ BumpVectorContext &getBumpVectorContext() {
+ return BlkBVC;
}
private:
CFGBlock* Entry;
CFGBlock* Exit;
CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
- // for indirect gotos
- CFGBlockListTy Blocks;
+ // for indirect gotos
unsigned NumBlockIDs;
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
// It represents a map from Expr* to integers to record the set of
// block-level expressions and their "statement number" in the CFG.
void* BlkExprMap;
+
+ BumpVectorContext BlkBVC;
+
+ CFGBlockListTy Blocks;
- /// Alloc - An internal allocator.
- llvm::BumpPtrAllocator Alloc;
};
} // end namespace clang
class VISIBILITY_HIDDEN CFGBuilder {
ASTContext *Context;
CFG* cfg;
+
CFGBlock* Block;
CFGBlock* Succ;
CFGBlock* ContinueTargetBlock;
LabelSetTy AddressTakenLabels;
public:
- explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
+ explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG
+ Block(NULL), Succ(NULL),
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {
- // Create an empty CFG.
- cfg = new CFG();
- }
+ SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {}
~CFGBuilder() { delete cfg; }
CFGBlock *createBlock(bool add_successor = true);
bool FinishBlock(CFGBlock* B);
CFGBlock *addStmt(Stmt *S) { return Visit(S, true); }
-
+
+ void AppendStmt(CFGBlock *B, Stmt *S) {
+ B->appendStmt(S, cfg->getBumpVectorContext());
+ }
+
+ void AddSuccessor(CFGBlock *B, CFGBlock *S) {
+ B->addSuccessor(S, cfg->getBumpVectorContext());
+ }
/// TryResult - a class representing a variant over the values
/// 'true', 'false', or 'unknown'. This is returned by TryEvaluateBool,
// this is the first block added to the CFG, it will be implicitly registered
// as the exit block.
Succ = createBlock();
- assert (Succ == &cfg->getExit());
+ assert(Succ == &cfg->getExit());
Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
// Visit the statements and create the CFG.
// incomplete AST. Handle this by not registering a successor.
if (LI == LabelMap.end()) continue;
- B->addSuccessor(LI->second);
+ AddSuccessor(B, LI->second);
}
// Add successors to the Indirect Goto Dispatch block (if we have one).
// at an incomplete AST. Handle this by not registering a successor.
if (LI == LabelMap.end()) continue;
- B->addSuccessor(LI->second);
+ AddSuccessor(B, LI->second);
}
Succ = B;
CFGBlock* CFGBuilder::createBlock(bool add_successor) {
CFGBlock* B = cfg->createBlock();
if (add_successor && Succ)
- B->addSuccessor(Succ);
+ AddSuccessor(B, Succ);
return B;
}
CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) {
if (alwaysAdd) {
autoCreateBlock();
- Block->appendStmt(S);
+ AppendStmt(Block, S);
}
return VisitChildren(S);
if (alwaysAdd) {
autoCreateBlock();
- Block->appendStmt(A);
+ AppendStmt(Block, A);
}
return Block;
CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
if (B->isLogicalOp()) { // && or ||
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- ConfluenceBlock->appendStmt(B);
+ AppendStmt(ConfluenceBlock, B);
if (!FinishBlock(ConfluenceBlock))
return 0;
// Now link the LHSBlock with RHSBlock.
if (B->getOpcode() == BinaryOperator::LOr) {
- LHSBlock->addSuccessor(KnownVal.isTrue() ? NULL : ConfluenceBlock);
- LHSBlock->addSuccessor(KnownVal.isFalse() ? NULL : RHSBlock);
+ AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
+ AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
} else {
assert (B->getOpcode() == BinaryOperator::LAnd);
- LHSBlock->addSuccessor(KnownVal.isFalse() ? NULL : RHSBlock);
- LHSBlock->addSuccessor(KnownVal.isTrue() ? NULL : ConfluenceBlock);
+ AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
+ AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
}
// Generate the blocks for evaluating the LHS.
}
else if (B->getOpcode() == BinaryOperator::Comma) { // ,
autoCreateBlock();
- Block->appendStmt(B);
+ AppendStmt(Block, B);
addStmt(B->getRHS());
return addStmt(B->getLHS());
}
// If there is no target for the break, then we are looking at an incomplete
// AST. This means that the CFG cannot be constructed.
if (BreakTargetBlock)
- Block->addSuccessor(BreakTargetBlock);
+ AddSuccessor(Block, BreakTargetBlock);
else
badCFG = true;
// Create new block with no successor for the remaining pieces.
Block = createBlock(false);
- Block->appendStmt(C);
+ AppendStmt(Block, C);
// Wire this to the exit block directly.
- Block->addSuccessor(&cfg->getExit());
+ AddSuccessor(Block, &cfg->getExit());
return VisitChildren(C);
}
CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) {
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
+ AppendStmt(ConfluenceBlock, C);
if (!FinishBlock(ConfluenceBlock))
return 0;
Block = createBlock(false);
// See if this is a known constant.
const TryResult& KnownVal = TryEvaluateBool(C->getCond());
- Block->addSuccessor(KnownVal.isFalse() ? NULL : LHSBlock);
- Block->addSuccessor(KnownVal.isTrue() ? NULL : RHSBlock);
+ AddSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
+ AddSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
Block->setTerminator(C);
return addStmt(C->getCond());
}
// Create the confluence block that will "merge" the results of the ternary
// expression.
CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
+ AppendStmt(ConfluenceBlock, C);
if (!FinishBlock(ConfluenceBlock))
return 0;
// See if this is a known constant.
const TryResult& KnownVal = TryEvaluateBool(C->getCond());
if (LHSBlock) {
- Block->addSuccessor(KnownVal.isFalse() ? NULL : LHSBlock);
+ AddSuccessor(Block, KnownVal.isFalse() ? NULL : LHSBlock);
} else {
if (KnownVal.isFalse()) {
// If we know the condition is false, add NULL as the successor for
// the block containing the condition. In this case, the confluence
// block will have just one predecessor.
- Block->addSuccessor(0);
+ AddSuccessor(Block, 0);
assert(ConfluenceBlock->pred_size() == 1);
} else {
// If we have no LHS expression, add the ConfluenceBlock as a direct
// the RHSBlock will have been added to the succcessors already, and we
// want the first predecessor to the the block containing the expression
// for the case when the ternary expression evaluates to true.
- Block->addSuccessor(ConfluenceBlock);
+ AddSuccessor(Block, ConfluenceBlock);
assert(ConfluenceBlock->pred_size() == 2);
std::reverse(ConfluenceBlock->pred_begin(),
ConfluenceBlock->pred_end());
}
}
- Block->addSuccessor(KnownVal.isTrue() ? NULL : RHSBlock);
+ AddSuccessor(Block, KnownVal.isTrue() ? NULL : RHSBlock);
Block->setTerminator(C);
return addStmt(C->getCond());
}
autoCreateBlock();
if (DS->isSingleDecl()) {
- Block->appendStmt(DS);
+ AppendStmt(Block, DS);
return VisitDeclSubExpr(DS->getSingleDecl());
}
DeclStmt *DSNew = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
// Append the fake DeclStmt to block.
- Block->appendStmt(DSNew);
+ AppendStmt(Block, DSNew);
B = VisitDeclSubExpr(D);
}
// Create an empty block so we can distinguish between true and false
// branches in path-sensitive analyses.
ThenBlock = createBlock(false);
- ThenBlock->addSuccessor(sv.get());
+ AddSuccessor(ThenBlock, sv.get());
} else if (Block) {
if (!FinishBlock(ThenBlock))
return 0;
const TryResult &KnownVal = TryEvaluateBool(I->getCond());
// Now add the successors.
- Block->addSuccessor(KnownVal.isFalse() ? NULL : ThenBlock);
- Block->addSuccessor(KnownVal.isTrue()? NULL : ElseBlock);
+ AddSuccessor(Block, KnownVal.isFalse() ? NULL : ThenBlock);
+ AddSuccessor(Block, KnownVal.isTrue()? NULL : ElseBlock);
// Add the condition as the last statement in the new block. This may create
// new blocks as the condition may contain control-flow. Any newly created
Block = createBlock(false);
// The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
+ AddSuccessor(Block, &cfg->getExit());
// Add the return statement to the block. This may create new blocks if R
// contains control-flow (short-circuit operations).
// We will need to backpatch this block later.
BackpatchBlocks.push_back(Block);
else
- Block->addSuccessor(I->second);
+ AddSuccessor(Block, I->second);
return Block;
}
return 0;
// This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(KnownVal.isFalse() ? NULL : BodyBlock);
+ AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
}
// Link up the condition block with the code that follows the loop. (the
// false branch).
- ExitConditionBlock->addSuccessor(KnownVal.isTrue() ? NULL : LoopSuccessor);
+ AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
// If the loop contains initialization, create a new block for those
// statements. This block can also contain statements that precede the loop.
// The last statement in the block should be the ObjCForCollectionStmt, which
// performs the actual binding to 'element' and determines if there are any
// more items in the collection.
- ExitConditionBlock->appendStmt(S);
+ AppendStmt(ExitConditionBlock, S);
Block = ExitConditionBlock;
// Walk the 'element' expression to see if there are any side-effects. We
}
// This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
+ AddSuccessor(ExitConditionBlock, BodyBlock);
}
// Link up the condition block with the code that follows the loop.
// (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
+ AddSuccessor(ExitConditionBlock, LoopSuccessor);
// Now create a prologue block to contain the collection expression.
Block = createBlock();
}
// Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(KnownVal.isFalse() ? NULL : BodyBlock);
+ AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : BodyBlock);
}
// Link up the condition block with the code that follows the loop. (the
// false branch).
- ExitConditionBlock->addSuccessor(KnownVal.isTrue() ? NULL : LoopSuccessor);
+ AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
// There can be no more statements in the condition block since we loop back
// to this block. NULL out Block to force lazy creation of another block.
Block = createBlock(false);
// The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
+ AddSuccessor(Block, &cfg->getExit());
// Add the statement to the block. This may create new blocks if S contains
// control-flow (short-circuit operations).
Block = createBlock(false);
// The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
+ AddSuccessor(Block, &cfg->getExit());
// Add the statement to the block. This may create new blocks if S contains
// control-flow (short-circuit operations).
LoopBackBlock->setLoopTarget(D);
// Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(KnownVal.isFalse() ? NULL : LoopBackBlock);
+ AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : LoopBackBlock);
}
// Link up the condition block with the code that follows the loop.
// (the false branch).
- ExitConditionBlock->addSuccessor(KnownVal.isTrue() ? NULL : LoopSuccessor);
+ AddSuccessor(ExitConditionBlock, KnownVal.isTrue() ? NULL : LoopSuccessor);
// There can be no more statements in the body block(s) since we loop back to
// the body. NULL out Block to force lazy creation of another block.
// If there is no target for the continue, then we are looking at an
// incomplete AST. This means the CFG cannot be constructed.
if (ContinueTargetBlock)
- Block->addSuccessor(ContinueTargetBlock);
+ AddSuccessor(Block, ContinueTargetBlock);
else
badCFG = true;
if (alwaysAdd) {
autoCreateBlock();
- Block->appendStmt(E);
+ AppendStmt(Block, E);
}
// VLA types have expressions that must be evaluated.
CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) {
if (alwaysAdd) {
autoCreateBlock();
- Block->appendStmt(SE);
+ AppendStmt(Block, SE);
}
return VisitCompoundStmt(SE->getSubStmt());
}
// If we have no "default:" case, the default transition is to the code
// following the switch body.
- SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock);
+ AddSuccessor(SwitchTerminatedBlock, DefaultCaseBlock);
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
// Add this block to the list of successors for the block with the switch
// statement.
assert(SwitchTerminatedBlock);
- SwitchTerminatedBlock->addSuccessor(CaseBlock);
+ AddSuccessor(SwitchTerminatedBlock, CaseBlock);
// We set Block to NULL to allow lazy creation of a new block (if necessary)
Block = NULL;
Block = createBlock(false);
Block->setTerminator(I);
- Block->addSuccessor(IBlock);
+ AddSuccessor(Block, IBlock);
return addStmt(I->getTarget());
}
bool first_block = begin() == end();
// Create the block.
- Blocks.push_front(CFGBlock(NumBlockIDs++));
+ CFGBlock *Mem = getAllocator().Allocate<CFGBlock>();
+ new (Mem) CFGBlock(NumBlockIDs++, BlkBVC);
+ Blocks.push_back(Mem, BlkBVC);
// If this is the first block, set it as the Entry and Exit.
- if (first_block) Entry = Exit = &front();
+ if (first_block)
+ Entry = Exit = &back();
// Return the block.
- return &front();
+ return &back();
}
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
llvm::SmallPtrSet<Expr*,50> SubExprAssignments;
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
- for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
+ for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
FindSubExprAssignments(*BI, SubExprAssignments);
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
// Iterate over the statements again on identify the Expr* and Stmt* at the
// block-level that are block-level expressions.
- for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
+ for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
if (Expr* Exp = dyn_cast<Expr>(*BI)) {
if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
// Look at terminators. The condition is a block-level expression.
- Stmt* S = I->getTerminatorCondition();
+ Stmt* S = (*I)->getTerminatorCondition();
if (S && M->find(S) == M->end()) {
unsigned x = M->size();
: CurrentBlock(0), CurrentStmt(0), LangOpts(LO) {
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
- for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ;
+ for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j )
- StmtMap[*BI] = std::make_pair(I->getBlockID(),j);
+ StmtMap[*BI] = std::make_pair((*I)->getBlockID(),j);
}
}
// Iterate through the CFGBlocks and print them one by one.
for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
// Skip the entry block, because we already printed it.
- if (&(*I) == &getEntry() || &(*I) == &getExit())
+ if (&(**I) == &getEntry() || &(**I) == &getExit())
continue;
- print_block(OS, this, *I, &Helper, true);
+ print_block(OS, this, **I, &Helper, true);
}
// Print the exit block.