[cfe-commits] r114790 - /cfe/trunk/lib/Analysis/CFG.cpp
Marcin Swiderski
marcin.sfider at gmail.com
Sat Sep 25 04:05:21 PDT 2010
Author: sfider
Date: Sat Sep 25 06:05:21 2010
New Revision: 114790
URL: http://llvm.org/viewvc/llvm-project?rev=114790&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Analysis/CFG.cpp
Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=114790&r1=114789&r2=114790&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Sat Sep 25 06:05:21 2010
@@ -52,6 +52,116 @@
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 @@
/// 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
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::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 @@
// 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 @@
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 @@
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 @@
// 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::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 @@
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 @@
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* 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 @@
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 @@
// 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 @@
// 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 @@
// 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
More information about the cfe-commits
mailing list