In preparation for adding generation of destructors for objects with automatic storage added:

- LocalScope class with iterator used to pointing into it,
- fat doxygen comment for LocalScope indended usage,
- BlockScopePosPair class used for storing jump targets/sources (for: goto, break, continue), that replaces raw CFGBlock pointer used earlier for this purpose.

llvm-svn: 114790
This commit is contained in:
Marcin Swiderski 2010-09-25 11:05:21 +00:00
parent d6142976de
commit 8b99b8a782
1 changed files with 166 additions and 43 deletions

View File

@ -52,6 +52,116 @@ private:
Kind k;
};
/// LocalScope - Node in tree of local scopes created for C++ implicit
/// destructor calls generation. It contains list of automatic variables
/// declared in the scope and link to position in previous scope this scope
/// began in.
///
/// The process of creating local scopes is as follows:
/// - Init CFGBuilder::ScopePos with invalid position (equivalent for null),
/// - Before processing statements in scope (e.g. CompoundStmt) create
/// LocalScope object using CFGBuilder::ScopePos as link to previous scope
/// and set CFGBuilder::ScopePos to the end of new scope,
/// - On every occurance of VarDecl increase CFGBuilder::ScopePos if it points
/// at this VarDecl,
/// - For every normal (without jump) end of scope add to CFGBlock destructors
/// for objects in the current scope,
/// - For every jump add to CFGBlock destructors for objects
/// between CFGBuilder::ScopePos and local scope position saved for jump
/// target. Thanks to C++ restrictions on goto jumps we can be sure that
/// jump target position will be on the path to root from CFGBuilder::ScopePos
/// (adding any variable that doesn't need constructor to be called to
/// LocalScope can break this assumption),
///
class LocalScope {
public:
typedef llvm::SmallVector<VarDecl*, 4> AutomaticVarsTy;
/// const_iterator - Iterates local scope backwards and jumps to previous
/// scope on reaching the begining of currently iterated scope.
class const_iterator {
const LocalScope* Scope;
/// VarIter is guaranteed to be greater then 0 for every valid iterator.
/// Invalid iterator (with null Scope) has VarIter equal to 0.
unsigned VarIter;
public:
/// Create invalid iterator. Dereferencing invalid iterator is not allowed.
/// Incrementing invalid iterator is allowed and will result in invalid
/// iterator.
const_iterator()
: Scope(NULL), VarIter(0) {}
/// Create valid iterator. In case when S.Prev is an invalid iterator and
/// I is equal to 0, this will create invalid iterator.
const_iterator(const LocalScope& S, unsigned I)
: Scope(&S), VarIter(I) {
// Iterator to "end" of scope is not allowed. Handle it by going up
// in scopes tree possibly up to invalid iterator in the root.
if (VarIter == 0 && Scope)
*this = Scope->Prev;
}
VarDecl* const* operator->() const {
assert (Scope && "Dereferencing invalid iterator is not allowed");
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
return &Scope->Vars[VarIter - 1];
}
VarDecl* operator*() const {
return *this->operator->();
}
const_iterator& operator++() {
if (!Scope)
return *this;
assert (VarIter != 0 && "Iterator has invalid value of VarIter member");
--VarIter;
if (VarIter == 0)
*this = Scope->Prev;
return *this;
}
bool operator==(const const_iterator& rhs) const {
return Scope == rhs.Scope && VarIter == rhs.VarIter;
}
bool operator!=(const const_iterator& rhs) const {
return !(*this == rhs);
}
};
friend class const_iterator;
private:
/// Automatic variables in order of declaration.
AutomaticVarsTy Vars;
/// Iterator to variable in previous scope that was declared just before
/// begin of this scope.
const_iterator Prev;
public:
/// Constructs empty scope linked to previous scope in specified place.
LocalScope(const_iterator P)
: Vars()
, Prev(P) {}
/// Begin of scope in direction of CFG building (backwards).
const_iterator begin() const { return const_iterator(*this, Vars.size()); }
};
/// BlockScopePosPair - Structure for specifing position in CFG during its build
/// proces. It consists of CFGBlock that specifies position in CFG graph and
/// LocalScope::const_iterator that specifies position in LocalScope graph.
struct BlockScopePosPair {
BlockScopePosPair() {}
BlockScopePosPair(CFGBlock* B, LocalScope::const_iterator S)
: Block(B), ScopePos(S) {}
CFGBlock* Block;
LocalScope::const_iterator ScopePos;
};
/// CFGBuilder - This class implements CFG construction from an AST.
/// The builder is stateful: an instance of the builder should be used to only
/// construct a single CFG.
@ -67,24 +177,30 @@ private:
/// implicit fall-throughs without extra basic blocks.
///
class CFGBuilder {
typedef BlockScopePosPair JumpTarget;
typedef BlockScopePosPair JumpSource;
ASTContext *Context;
llvm::OwningPtr<CFG> cfg;
CFGBlock* Block;
CFGBlock* Succ;
CFGBlock* ContinueTargetBlock;
CFGBlock* BreakTargetBlock;
JumpTarget ContinueJumpTarget;
JumpTarget BreakJumpTarget;
CFGBlock* SwitchTerminatedBlock;
CFGBlock* DefaultCaseBlock;
CFGBlock* TryTerminatedBlock;
// LabelMap records the mapping from Label expressions to their blocks.
typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
// Current position in local scope.
LocalScope::const_iterator ScopePos;
// LabelMap records the mapping from Label expressions to their jump targets.
typedef llvm::DenseMap<LabelStmt*, JumpTarget> 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;
typedef std::vector<JumpSource> BackpatchBlocksTy;
BackpatchBlocksTy BackpatchBlocks;
// A list of labels whose address has been taken (for indirect gotos).
@ -97,7 +213,6 @@ class CFGBuilder {
public:
explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG
Block(NULL), Succ(NULL),
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
TryTerminatedBlock(NULL), badCFG(false) {}
@ -259,7 +374,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
E = BackpatchBlocks.end(); I != E; ++I ) {
CFGBlock* B = *I;
CFGBlock* B = I->Block;
GotoStmt* G = cast<GotoStmt>(B->getTerminator());
LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
@ -267,7 +382,8 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
// incomplete AST. Handle this by not registering a successor.
if (LI == LabelMap.end()) continue;
AddSuccessor(B, LI->second);
JumpTarget JT = LI->second;
AddSuccessor(B, JT.Block);
}
// Add successors to the Indirect Goto Dispatch block (if we have one).
@ -282,7 +398,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
// at an incomplete AST. Handle this by not registering a successor.
if (LI == LabelMap.end()) continue;
AddSuccessor(B, LI->second);
AddSuccessor(B, LI->second.Block);
}
// Create an empty entry block that has no predecessors.
@ -549,9 +665,9 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
// 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)
AddSuccessor(Block, BreakTargetBlock);
else
if (BreakJumpTarget.Block) {
AddSuccessor(Block, BreakJumpTarget.Block);
} else
badCFG = true;
@ -921,7 +1037,7 @@ CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
LabelBlock = createBlock(); // scopes that only contains NullStmts.
assert(LabelMap.find(L) == LabelMap.end() && "label already in map");
LabelMap[ L ] = LabelBlock;
LabelMap[ L ] = JumpTarget(LabelBlock, ScopePos);
// Labels partition blocks, so this is the end of the basic block we were
// processing (L is the block's label). Because this is label (and we have
@ -952,9 +1068,11 @@ CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
if (I == LabelMap.end())
// We will need to backpatch this block later.
BackpatchBlocks.push_back(Block);
else
AddSuccessor(Block, I->second);
BackpatchBlocks.push_back(JumpSource(Block, ScopePos));
else {
JumpTarget JT = I->second;
AddSuccessor(Block, JT.Block);
}
return Block;
}
@ -962,6 +1080,8 @@ CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
CFGBlock* LoopSuccessor = NULL;
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
// "for" is a control-flow statement. Thus we stop processing the current
// block.
if (Block) {
@ -973,8 +1093,8 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Save the current value for the break targets.
// All breaks should go to the code following the loop.
SaveAndRestore<CFGBlock*> save_break(BreakTargetBlock);
BreakTargetBlock = LoopSuccessor;
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, LoopBeginScopePos);
// Because of short-circuit evaluation, the condition of the loop can span
// multiple basic blocks. Thus we need the "Entry" and "Exit" blocks that
@ -1025,8 +1145,8 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
assert(F->getBody());
// Save the current values for Block, Succ, and continue targets.
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
save_continue(ContinueTargetBlock);
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
// Create a new block to contain the (bottom) of the loop body.
Block = NULL;
@ -1050,18 +1170,18 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
Block = 0;
}
ContinueTargetBlock = Succ;
ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
// The starting block for the loop increment is the block that should
// represent the 'loop target' for looping back to the start of the loop.
ContinueTargetBlock->setLoopTarget(F);
ContinueJumpTarget.Block->setLoopTarget(F);
// Now populate the body block, and in the process create new blocks as we
// walk the body of the loop.
CFGBlock* BodyBlock = addStmt(F->getBody());
if (!BodyBlock)
BodyBlock = ContinueTargetBlock; // can happen for "for (...;...;...) ;"
BodyBlock = ContinueJumpTarget.Block;//can happen for "for (...;...;...);"
else if (badCFG)
return 0;
@ -1170,11 +1290,12 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
// Now create the true branch.
{
// Save the current values for Succ, continue and break targets.
SaveAndRestore<CFGBlock*> save_Succ(Succ),
save_continue(ContinueTargetBlock), save_break(BreakTargetBlock);
SaveAndRestore<CFGBlock*> save_Succ(Succ);
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
save_break(BreakJumpTarget);
BreakTargetBlock = LoopSuccessor;
ContinueTargetBlock = EntryConditionBlock;
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
CFGBlock* BodyBlock = addStmt(S->getBody());
@ -1230,6 +1351,8 @@ CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
CFGBlock* LoopSuccessor = NULL;
LocalScope::const_iterator LoopBeginScopePos = ScopePos;
// "while" is a control-flow statement. Thus we stop processing the current
// block.
if (Block) {
@ -1285,9 +1408,9 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
assert(W->getBody());
// Save the current values for Block, Succ, and continue and break targets
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
save_continue(ContinueTargetBlock),
save_break(BreakTargetBlock);
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
save_break(BreakJumpTarget);
// Create an empty block to represent the transition block for looping back
// to the head of the loop.
@ -1295,10 +1418,10 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
assert(Succ == EntryConditionBlock);
Succ = createBlock();
Succ->setLoopTarget(W);
ContinueTargetBlock = Succ;
ContinueJumpTarget = JumpTarget(Succ, LoopBeginScopePos);
// All breaks should go to the code following the loop.
BreakTargetBlock = LoopSuccessor;
BreakJumpTarget = JumpTarget(LoopSuccessor, LoopBeginScopePos);
// NULL out Block to force lazy instantiation of blocks for the body.
Block = NULL;
@ -1307,7 +1430,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
CFGBlock* BodyBlock = addStmt(W->getBody());
if (!BodyBlock)
BodyBlock = ContinueTargetBlock; // can happen for "while(...) ;"
BodyBlock = ContinueJumpTarget.Block; // can happen for "while(...) ;"
else if (Block) {
if (badCFG)
return 0;
@ -1420,15 +1543,15 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
assert(D->getBody());
// Save the current values for Block, Succ, and continue and break targets
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
save_continue(ContinueTargetBlock),
save_break(BreakTargetBlock);
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
save_break(BreakJumpTarget);
// All continues within this loop should go to the condition block
ContinueTargetBlock = EntryConditionBlock;
ContinueJumpTarget = JumpTarget(EntryConditionBlock, ScopePos);
// All breaks should go to the code following the loop.
BreakTargetBlock = LoopSuccessor;
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// NULL out Block to force lazy instantiation of blocks for the body.
Block = NULL;
@ -1486,9 +1609,9 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
// 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)
AddSuccessor(Block, ContinueTargetBlock);
else
if (ContinueJumpTarget.Block) {
AddSuccessor(Block, ContinueJumpTarget.Block);
} else
badCFG = true;
return Block;
@ -1535,8 +1658,8 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
// Save the current "switch" context.
SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
save_break(BreakTargetBlock),
save_default(DefaultCaseBlock);
SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
// Set the "default" case to be the block after the switch statement. If the
// switch statement contains a "default:", this value will be overwritten with
@ -1549,7 +1672,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
// Now process the switch body. The code after the switch is the implicit
// successor.
Succ = SwitchSuccessor;
BreakTargetBlock = SwitchSuccessor;
BreakJumpTarget = JumpTarget(SwitchSuccessor, ScopePos);
// When visiting the body, the case statements should automatically get linked
// up to the switch. We also don't keep a pointer to the body, since all