[cfe-commits] r41332 - /cfe/trunk/AST/CFG.cpp
Ted Kremenek
kremenek at apple.com
Thu Aug 23 11:43:25 PDT 2007
Author: kremenek
Date: Thu Aug 23 13:43:24 2007
New Revision: 41332
URL: http://llvm.org/viewvc/llvm-project?rev=41332&view=rev
Log:
Added support for switch, default, and case statements in source-level CFGs.
Modified:
cfe/trunk/AST/CFG.cpp
Modified: cfe/trunk/AST/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/AST/CFG.cpp?rev=41332&r1=41331&r2=41332&view=diff
==============================================================================
--- cfe/trunk/AST/CFG.cpp (original)
+++ cfe/trunk/AST/CFG.cpp Thu Aug 23 13:43:24 2007
@@ -56,6 +56,7 @@
CFGBlock* Succ;
CFGBlock* ContinueTargetBlock;
CFGBlock* BreakTargetBlock;
+ CFGBlock* SwitchTerminatedBlock;
unsigned NumBlocks;
typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
@@ -67,6 +68,7 @@
public:
explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
+ SwitchTerminatedBlock(NULL),
NumBlocks(0) {
// Create an empty CFG.
cfg = new CFG();
@@ -139,8 +141,11 @@
CFGBlock::iterator I = B->begin();
if (I != B->end()) {
Stmt* S = *I;
- if (S->getStmtClass() != Stmt::LabelStmtClass)
- B->reverseStmts();
+
+ if (isa<LabelStmt>(S) || isa<SwitchCase>(S))
+ return;
+
+ B->reverseStmts();
}
}
@@ -535,6 +540,72 @@
return Block;
}
+ CFGBlock* VisitSwitchStmt(SwitchStmt* S) {
+ // "switch" is a control-flow statement. Thus we stop processing the
+ // current block.
+ CFGBlock* SwitchSuccessor = NULL;
+
+ if (Block) {
+ FinishBlock(Block);
+ SwitchSuccessor = Block;
+ }
+ else SwitchSuccessor = Succ;
+
+ // Save the current "switch" context.
+ SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
+ save_break(BreakTargetBlock);
+
+ // Create a new block that will contain the switch statement.
+ SwitchTerminatedBlock = createBlock(false);
+
+ // Add the terminator and condition in the switch block.
+ assert (S->getCond() && "switch condition must be non-NULL");
+ SwitchTerminatedBlock->appendStmt(S->getCond());
+ SwitchTerminatedBlock->setTerminator(S);
+
+
+ // Now process the switch body. The code after the switch is the implicit
+ // successor.
+ Succ = SwitchSuccessor;
+ BreakTargetBlock = SwitchSuccessor;
+
+ assert (S->getBody() && "switch must contain a non-NULL body");
+ Block = NULL;
+
+ // 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 control-flow from the switch goes to case/default statements.
+ Visit(S->getBody());
+
+ Block = SwitchTerminatedBlock;
+ return SwitchTerminatedBlock;
+ }
+
+ CFGBlock* VisitSwitchCase(SwitchCase* S) {
+ // A SwitchCase is either a "default" or "case" statement. We handle
+ // both in the same way. They are essentially labels, so they are the
+ // first statement in a block.
+ CFGBlock* CaseBlock = Visit(S->getSubStmt());
+ assert (CaseBlock);
+
+ // Cases/Default statements parition block, so this is the top of
+ // the basic block we were processing (the case/default is the first stmt).
+ CaseBlock->appendStmt(S);
+ FinishBlock(CaseBlock);
+
+ // Add this block to the list of successors for the block with the
+ // switch statement.
+ if (SwitchTerminatedBlock) SwitchTerminatedBlock->addSuccessor(CaseBlock);
+
+ // We set Block to NULL to allow lazy creation of a new block (if necessary)
+ Block = NULL;
+
+ // This block is now the implicit successor of other blocks.
+ Succ = CaseBlock;
+
+ return CaseBlock;
+ }
+
};
More information about the cfe-commits
mailing list