summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-04-28 00:51:56 +0000
committerTed Kremenek <kremenek@apple.com>2009-04-28 00:51:56 +0000
commit3575f84e459033d6427b84b4b795b22c85c4d27d (patch)
tree3558c52f1a3cea85a0b9db6e8e490c629bfcf0e8
parentf01fdff97b245caac98100d232c760b4d0531411 (diff)
downloadclang-3575f84e459033d6427b84b4b795b22c85c4d27d.tar.gz
CFG:
- Add 'LoopTarget' pointer field to CFGBlock. This records if the block is used as the 'loop back' path back to the head of a loop. - For ForStmt, encode the loop back target as the increment code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70274 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/CFG.h14
-rw-r--r--lib/AST/CFG.cpp28
2 files changed, 28 insertions, 14 deletions
diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h
index 0b179f9edf..7a9ee01d4f 100644
--- a/include/clang/AST/CFG.h
+++ b/include/clang/AST/CFG.h
@@ -61,12 +61,17 @@ class CFGBlock {
/// Label - An (optional) label that prefixes the executable
/// statements in the block. When this variable is non-NULL, it is
/// either an instance of LabelStmt or SwitchCase.
- Stmt* Label;
+ Stmt *Label;
/// Terminator - The terminator for a basic block that
/// indicates the type of control-flow that occurs between a block
/// and its successors.
- Stmt* Terminator;
+ Stmt *Terminator;
+
+ /// LoopTarget - Some blocks are used to represent the "loop edge" to
+ /// the start of a loop from within the loop body. This Stmt* will be
+ /// refer to the loop statement for such blocks (and be null otherwise).
+ const Stmt *LoopTarget;
/// BlockID - A numerical ID assigned to a CFGBlock during construction
/// of the CFG.
@@ -80,7 +85,7 @@ class CFGBlock {
public:
explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL),
- BlockID(blockid) {}
+ LoopTarget(NULL), BlockID(blockid) {}
~CFGBlock() {};
// Statement iterators
@@ -149,6 +154,7 @@ public:
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; }
Stmt* getTerminator() { return Terminator; }
const Stmt* getTerminator() const { return Terminator; }
@@ -159,6 +165,8 @@ public:
return const_cast<CFGBlock*>(this)->getTerminatorCondition();
}
+ const Stmt *getLoopTarget() const { return LoopTarget; }
+
bool hasBinaryBranchTerminator() const;
Stmt* getLabel() { return Label; }
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
index 14c93f398e..00f5960e11 100644
--- a/lib/AST/CFG.cpp
+++ b/lib/AST/CFG.cpp
@@ -752,21 +752,27 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Generate increment code in its own basic block. This is the target
// of continue statements.
Succ = Visit(I);
-
- // Finish up the increment block if it hasn't been already.
- if (Block) {
- assert (Block == Succ);
- FinishBlock(Block);
- Block = 0;
- }
-
- ContinueTargetBlock = Succ;
}
else {
- // No increment code. Continues should go the the entry condition block.
- ContinueTargetBlock = EntryConditionBlock;
+ // No increment code. Create a special, empty, block that is used as
+ // the target block for "looping back" to the start of the loop.
+ assert(Succ == EntryConditionBlock);
+ Succ = createBlock();
}
+ // Finish up the increment (or empty) block if it hasn't been already.
+ if (Block) {
+ assert(Block == Succ);
+ FinishBlock(Block);
+ Block = 0;
+ }
+
+ ContinueTargetBlock = Succ;
+
+ // 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);
+
// All breaks should go to the code following the loop.
BreakTargetBlock = LoopSuccessor;