aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/CFG.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-07-16 18:13:04 +0000
committerTed Kremenek <kremenek@apple.com>2009-07-16 18:13:04 +0000
commite41611aa2237d06a0ef61db4528fb2883a8defcd (patch)
treeccabdf5223628e33f1f7a3f508d1dd507854bb84 /lib/AST/CFG.cpp
parent0d9ff0bcba53da358cce7170cc60e8ee3b7f6676 (diff)
Move the source-level CFG from libAST to libAnalysis.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76092 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/CFG.cpp')
-rw-r--r--lib/AST/CFG.cpp1924
1 files changed, 0 insertions, 1924 deletions
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
deleted file mode 100644
index 69852f5fea..0000000000
--- a/lib/AST/CFG.cpp
+++ /dev/null
@@ -1,1924 +0,0 @@
-//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CFG and CFGBuilder classes for representing and
-// building Control-Flow Graphs (CFGs) from ASTs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/CFG.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Streams.h"
-#include "llvm/Support/Compiler.h"
-#include <llvm/Support/Allocator.h>
-#include <llvm/Support/Format.h>
-
-using namespace clang;
-
-namespace {
-
-// SaveAndRestore - A utility class that uses RIIA to save and restore
-// the value of a variable.
-template<typename T>
-struct VISIBILITY_HIDDEN SaveAndRestore {
- SaveAndRestore(T& x) : X(x), old_value(x) {}
- ~SaveAndRestore() { X = old_value; }
- T get() { return old_value; }
-
- T& X;
- T old_value;
-};
-
-static SourceLocation GetEndLoc(Decl* D) {
- if (VarDecl* VD = dyn_cast<VarDecl>(D))
- if (Expr* Ex = VD->getInit())
- return Ex->getSourceRange().getEnd();
-
- return D->getLocation();
-}
-
-/// 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.
-///
-/// Example usage:
-///
-/// CFGBuilder builder;
-/// CFG* cfg = builder.BuildAST(stmt1);
-///
-/// CFG construction is done via a recursive walk of an AST.
-/// We actually parse the AST in reverse order so that the successor
-/// of a basic block is constructed prior to its predecessor. This
-/// allows us to nicely capture implicit fall-throughs without extra
-/// basic blocks.
-///
-class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
- CFG* cfg;
- CFGBlock* Block;
- CFGBlock* Succ;
- CFGBlock* ContinueTargetBlock;
- CFGBlock* BreakTargetBlock;
- CFGBlock* SwitchTerminatedBlock;
- CFGBlock* DefaultCaseBlock;
-
- // LabelMap records the mapping from Label expressions to their blocks.
- typedef llvm::DenseMap<LabelStmt*,CFGBlock*> 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;
- BackpatchBlocksTy BackpatchBlocks;
-
- // A list of labels whose address has been taken (for indirect gotos).
- typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
- LabelSetTy AddressTakenLabels;
-
-public:
- explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
- ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {
- // Create an empty CFG.
- cfg = new CFG();
- }
-
- ~CFGBuilder() { delete cfg; }
-
- // buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(Stmt* Statement);
-
- // Visitors to walk an AST and construct the CFG. Called by
- // buildCFG. Do not call directly!
-
- CFGBlock* VisitBreakStmt(BreakStmt* B);
- CFGBlock* VisitCaseStmt(CaseStmt* Terminator);
- CFGBlock* VisitCompoundStmt(CompoundStmt* C);
- CFGBlock* VisitContinueStmt(ContinueStmt* C);
- CFGBlock* VisitDefaultStmt(DefaultStmt* D);
- CFGBlock* VisitDoStmt(DoStmt* D);
- CFGBlock* VisitForStmt(ForStmt* F);
- CFGBlock* VisitGotoStmt(GotoStmt* G);
- CFGBlock* VisitIfStmt(IfStmt* I);
- CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
- CFGBlock* VisitLabelStmt(LabelStmt* L);
- CFGBlock* VisitNullStmt(NullStmt* Statement);
- CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
- CFGBlock* VisitReturnStmt(ReturnStmt* R);
- CFGBlock* VisitStmt(Stmt* Statement);
- CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator);
- CFGBlock* VisitWhileStmt(WhileStmt* W);
-
- // FIXME: Add support for ObjC-specific control-flow structures.
-
- // NYS == Not Yet Supported
- CFGBlock* NYS() {
- badCFG = true;
- return Block;
- }
-
- CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S);
- CFGBlock* VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) {
- // FIXME: For now we pretend that @catch and the code it contains
- // does not exit.
- return Block;
- }
-
- // FIXME: This is not completely supported. We basically @throw like
- // a 'return'.
- CFGBlock* VisitObjCAtThrowStmt(ObjCAtThrowStmt* S);
-
- CFGBlock* VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S);
-
- // Blocks.
- CFGBlock* VisitBlockExpr(BlockExpr* E) { return NYS(); }
- CFGBlock* VisitBlockDeclRefExpr(BlockDeclRefExpr* E) { return NYS(); }
-
-private:
- CFGBlock* createBlock(bool add_successor = true);
- CFGBlock* addStmt(Stmt* Terminator);
- CFGBlock* WalkAST(Stmt* Terminator, bool AlwaysAddStmt);
- CFGBlock* WalkAST_VisitChildren(Stmt* Terminator);
- CFGBlock* WalkAST_VisitDeclSubExpr(Decl* D);
- CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* Terminator);
- bool FinishBlock(CFGBlock* B);
-
- bool badCFG;
-};
-
-// FIXME: Add support for dependent-sized array types in C++?
-// Does it even make sense to build a CFG for an uninstantiated template?
-static VariableArrayType* FindVA(Type* t) {
- while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
- if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
- if (vat->getSizeExpr())
- return vat;
-
- t = vt->getElementType().getTypePtr();
- }
-
- return 0;
-}
-
-/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can
-/// represent an arbitrary statement. Examples include a single expression
-/// or a function body (compound statement). The ownership of the returned
-/// CFG is transferred to the caller. If CFG construction fails, this method
-/// returns NULL.
-CFG* CFGBuilder::buildCFG(Stmt* Statement) {
- assert (cfg);
- if (!Statement) return NULL;
-
- badCFG = false;
-
- // Create an empty block that will serve as the exit block for the CFG.
- // Since this is the first block added to the CFG, it will be implicitly
- // registered as the exit block.
- Succ = createBlock();
- assert (Succ == &cfg->getExit());
- Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
-
- // Visit the statements and create the CFG.
- CFGBlock* B = Visit(Statement);
- if (!B) B = Succ;
-
- if (B) {
- // Finalize the last constructed block. This usually involves
- // reversing the order of the statements in the block.
- if (Block) FinishBlock(B);
-
- // Backpatch the gotos whose label -> block mappings we didn't know
- // when we encountered them.
- for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
- E = BackpatchBlocks.end(); I != E; ++I ) {
-
- CFGBlock* B = *I;
- GotoStmt* G = cast<GotoStmt>(B->getTerminator());
- LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
-
- // If there is no target for the goto, then we are looking at an
- // incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end()) continue;
-
- B->addSuccessor(LI->second);
- }
-
- // Add successors to the Indirect Goto Dispatch block (if we have one).
- if (CFGBlock* B = cfg->getIndirectGotoBlock())
- for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
- E = AddressTakenLabels.end(); I != E; ++I ) {
-
- // Lookup the target block.
- LabelMapTy::iterator LI = LabelMap.find(*I);
-
- // If there is no target block that contains label, then we are looking
- // at an incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end()) continue;
-
- B->addSuccessor(LI->second);
- }
-
- Succ = B;
- }
-
- // Create an empty entry block that has no predecessors.
- cfg->setEntry(createBlock());
-
- if (badCFG) {
- delete cfg;
- cfg = NULL;
- return NULL;
- }
-
- // NULL out cfg so that repeated calls to the builder will fail and that
- // the ownership of the constructed CFG is passed to the caller.
- CFG* t = cfg;
- cfg = NULL;
- return t;
-}
-
-/// createBlock - Used to lazily create blocks that are connected
-/// to the current (global) succcessor.
-CFGBlock* CFGBuilder::createBlock(bool add_successor) {
- CFGBlock* B = cfg->createBlock();
- if (add_successor && Succ) B->addSuccessor(Succ);
- return B;
-}
-
-/// FinishBlock - When the last statement has been added to the block,
-/// we must reverse the statements because they have been inserted
-/// in reverse order.
-bool CFGBuilder::FinishBlock(CFGBlock* B) {
- if (badCFG)
- return false;
-
- assert (B);
- B->reverseStmts();
- return true;
-}
-
-/// addStmt - Used to add statements/expressions to the current CFGBlock
-/// "Block". This method calls WalkAST on the passed statement to see if it
-/// contains any short-circuit expressions. If so, it recursively creates
-/// the necessary blocks for such expressions. It returns the "topmost" block
-/// of the created blocks, or the original value of "Block" when this method
-/// was called if no additional blocks are created.
-CFGBlock* CFGBuilder::addStmt(Stmt* Terminator) {
- if (!Block) Block = createBlock();
- return WalkAST(Terminator,true);
-}
-
-/// WalkAST - Used by addStmt to walk the subtree of a statement and
-/// add extra blocks for ternary operators, &&, and ||. We also
-/// process "," and DeclStmts (which may contain nested control-flow).
-CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
- switch (Terminator->getStmtClass()) {
- case Stmt::ConditionalOperatorClass: {
- ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
-
- // Create the confluence block that will "merge" the results
- // of the ternary expression.
- CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- // Create a block for the LHS expression if there is an LHS expression.
- // A GCC extension allows LHS to be NULL, causing the condition to
- // be the value that is returned instead.
- // e.g: x ?: y is shorthand for: x ? x : y;
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* LHSBlock = NULL;
- if (C->getLHS()) {
- LHSBlock = Visit(C->getLHS());
- if (!FinishBlock(LHSBlock))
- return 0;
- Block = NULL;
- }
-
- // Create the block for the RHS expression.
- Succ = ConfluenceBlock;
- CFGBlock* RHSBlock = Visit(C->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- // Create the block that will contain the condition.
- Block = createBlock(false);
-
- if (LHSBlock)
- Block->addSuccessor(LHSBlock);
- else {
- // If we have no LHS expression, add the ConfluenceBlock as a direct
- // successor for the block containing the condition. Moreover,
- // we need to reverse the order of the predecessors in the
- // ConfluenceBlock because 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);
- assert (ConfluenceBlock->pred_size() == 2);
- std::reverse(ConfluenceBlock->pred_begin(),
- ConfluenceBlock->pred_end());
- }
-
- Block->addSuccessor(RHSBlock);
-
- Block->setTerminator(C);
- return addStmt(C->getCond());
- }
-
- case Stmt::ChooseExprClass: {
- ChooseExpr* C = cast<ChooseExpr>(Terminator);
-
- CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* LHSBlock = Visit(C->getLHS());
- if (!FinishBlock(LHSBlock))
- return 0;
-
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* RHSBlock = Visit(C->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- Block = createBlock(false);
- Block->addSuccessor(LHSBlock);
- Block->addSuccessor(RHSBlock);
- Block->setTerminator(C);
- return addStmt(C->getCond());
- }
-
- case Stmt::DeclStmtClass: {
- DeclStmt *DS = cast<DeclStmt>(Terminator);
- if (DS->isSingleDecl()) {
- Block->appendStmt(Terminator);
- return WalkAST_VisitDeclSubExpr(DS->getSingleDecl());
- }
-
- CFGBlock* B = 0;
-
- // FIXME: Add a reverse iterator for DeclStmt to avoid this
- // extra copy.
- typedef llvm::SmallVector<Decl*,10> BufTy;
- BufTy Buf(DS->decl_begin(), DS->decl_end());
-
- for (BufTy::reverse_iterator I=Buf.rbegin(), E=Buf.rend(); I!=E; ++I) {
- // Get the alignment of the new DeclStmt, padding out to >=8 bytes.
- unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8
- ? 8 : llvm::AlignOf<DeclStmt>::Alignment;
-
- // Allocate the DeclStmt using the BumpPtrAllocator. It will
- // get automatically freed with the CFG.
- DeclGroupRef DG(*I);
- Decl* D = *I;
- void* Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A);
-
- DeclStmt* DS = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
-
- // Append the fake DeclStmt to block.
- Block->appendStmt(DS);
- B = WalkAST_VisitDeclSubExpr(D);
- }
- return B;
- }
-
- case Stmt::AddrLabelExprClass: {
- AddrLabelExpr* A = cast<AddrLabelExpr>(Terminator);
- AddressTakenLabels.insert(A->getLabel());
-
- if (AlwaysAddStmt) Block->appendStmt(Terminator);
- return Block;
- }
-
- case Stmt::StmtExprClass:
- return WalkAST_VisitStmtExpr(cast<StmtExpr>(Terminator));
-
- case Stmt::SizeOfAlignOfExprClass: {
- SizeOfAlignOfExpr* E = cast<SizeOfAlignOfExpr>(Terminator);
-
- // VLA types have expressions that must be evaluated.
- if (E->isArgumentType()) {
- for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- addStmt(VA->getSizeExpr());
- }
- // Expressions in sizeof/alignof are not evaluated and thus have no
- // control flow.
- else
- Block->appendStmt(Terminator);
-
- return Block;
- }
-
- case Stmt::BinaryOperatorClass: {
- BinaryOperator* B = cast<BinaryOperator>(Terminator);
-
- if (B->isLogicalOp()) { // && or ||
- CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
- ConfluenceBlock->appendStmt(B);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- // create the block evaluating the LHS
- CFGBlock* LHSBlock = createBlock(false);
- LHSBlock->setTerminator(B);
-
- // create the block evaluating the RHS
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* RHSBlock = Visit(B->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- // Now link the LHSBlock with RHSBlock.
- if (B->getOpcode() == BinaryOperator::LOr) {
- LHSBlock->addSuccessor(ConfluenceBlock);
- LHSBlock->addSuccessor(RHSBlock);
- }
- else {
- assert (B->getOpcode() == BinaryOperator::LAnd);
- LHSBlock->addSuccessor(RHSBlock);
- LHSBlock->addSuccessor(ConfluenceBlock);
- }
-
- // Generate the blocks for evaluating the LHS.
- Block = LHSBlock;
- return addStmt(B->getLHS());
- }
- else if (B->getOpcode() == BinaryOperator::Comma) { // ,
- Block->appendStmt(B);
- addStmt(B->getRHS());
- return addStmt(B->getLHS());
- }
-
- break;
- }
-
- // Blocks: No support for blocks ... yet
- case Stmt::BlockExprClass:
- case Stmt::BlockDeclRefExprClass:
- return NYS();
-
- case Stmt::ParenExprClass:
- return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt);
-
- default:
- break;
- };
-
- if (AlwaysAddStmt) Block->appendStmt(Terminator);
- return WalkAST_VisitChildren(Terminator);
-}
-
-/// WalkAST_VisitDeclSubExpr - Utility method to add block-level expressions
-/// for initializers in Decls.
-CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExpr(Decl* D) {
- VarDecl* VD = dyn_cast<VarDecl>(D);
-
- if (!VD)
- return Block;
-
- Expr* Init = VD->getInit();
-
- if (Init) {
- // Optimization: Don't create separate block-level statements for literals.
- switch (Init->getStmtClass()) {
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::StringLiteralClass:
- break;
- default:
- Block = addStmt(Init);
- }
- }
-
- // If the type of VD is a VLA, then we must process its size expressions.
- for (VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != 0;
- VA = FindVA(VA->getElementType().getTypePtr()))
- Block = addStmt(VA->getSizeExpr());
-
- return Block;
-}
-
-/// WalkAST_VisitChildren - Utility method to call WalkAST on the
-/// children of a Stmt.
-CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* Terminator) {
- CFGBlock* B = Block;
- for (Stmt::child_iterator I = Terminator->child_begin(),
- E = Terminator->child_end();
- I != E; ++I)
- if (*I) B = WalkAST(*I);
-
- return B;
-}
-
-/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement
-/// expressions (a GCC extension).
-CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* Terminator) {
- Block->appendStmt(Terminator);
- return VisitCompoundStmt(Terminator->getSubStmt());
-}
-
-/// VisitStmt - Handle statements with no branching control flow.
-CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) {
- // We cannot assume that we are in the middle of a basic block, since
- // the CFG might only be constructed for this single statement. If
- // we have no current basic block, just create one lazily.
- if (!Block) Block = createBlock();
-
- // Simply add the statement to the current block. We actually
- // insert statements in reverse order; this order is reversed later
- // when processing the containing element in the AST.
- addStmt(Statement);
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) {
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
-
- CFGBlock* LastBlock = Block;
-
- for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
- I != E; ++I ) {
- LastBlock = Visit(*I);
- }
-
- return LastBlock;
-}
-
-CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
- // We may see an if statement in the middle of a basic block, or
- // it may be the first statement we are processing. In either case,
- // we create a new basic block. First, we create the blocks for
- // the then...else statements, and then we create the block containing
- // the if statement. If we were in the middle of a block, we
- // stop processing that block and reverse its statements. That block
- // is then the implicit successor for the "then" and "else" clauses.
-
- // The block we were proccessing is now finished. Make it the
- // successor block.
- if (Block) {
- Succ = Block;
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Process the false branch. NULL out Block so that the recursive
- // call to Visit will create a new basic block.
- // Null out Block so that all successor
- CFGBlock* ElseBlock = Succ;
-
- if (Stmt* Else = I->getElse()) {
- SaveAndRestore<CFGBlock*> sv(Succ);
-
- // NULL out Block so that the recursive call to Visit will
- // create a new basic block.
- Block = NULL;
- ElseBlock = Visit(Else);
-
- if (!ElseBlock) // Can occur when the Else body has all NullStmts.
- ElseBlock = sv.get();
- else if (Block) {
- if (!FinishBlock(ElseBlock))
- return 0;
- }
- }
-
- // Process the true branch. NULL out Block so that the recursive
- // call to Visit will create a new basic block.
- // Null out Block so that all successor
- CFGBlock* ThenBlock;
- {
- Stmt* Then = I->getThen();
- assert (Then);
- SaveAndRestore<CFGBlock*> sv(Succ);
- Block = NULL;
- ThenBlock = Visit(Then);
-
- if (!ThenBlock) {
- // We can reach here if the "then" body has all NullStmts.
- // Create an empty block so we can distinguish between true and false
- // branches in path-sensitive analyses.
- ThenBlock = createBlock(false);
- ThenBlock->addSuccessor(sv.get());
- }
- else if (Block) {
- if (!FinishBlock(ThenBlock))
- return 0;
- }
- }
-
- // Now create a new block containing the if statement.
- Block = createBlock(false);
-
- // Set the terminator of the new block to the If statement.
- Block->setTerminator(I);
-
- // Now add the successors.
- Block->addSuccessor(ThenBlock);
- Block->addSuccessor(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 blocks will be pointed to be "Block".
- return addStmt(I->getCond()->IgnoreParens());
-}
-
-
-CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
- // If we were in the middle of a block we stop processing that block
- // and reverse its statements.
- //
- // NOTE: If a "return" appears in the middle of a block, this means
- // that the code afterwards is DEAD (unreachable). We still
- // keep a basic block for that code; a simple "mark-and-sweep"
- // from the entry block will be able to report such dead
- // blocks.
- if (Block) FinishBlock(Block);
-
- // Create the new block.
- Block = createBlock(false);
-
- // The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
-
- // Add the return statement to the block. This may create new blocks
- // if R contains control-flow (short-circuit operations).
- return addStmt(R);
-}
-
-CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
- // Get the block of the labeled statement. Add it to our map.
- Visit(L->getSubStmt());
- CFGBlock* LabelBlock = Block;
-
- if (!LabelBlock) // This can happen when the body is empty, i.e.
- LabelBlock=createBlock(); // scopes that only contains NullStmts.
-
- assert (LabelMap.find(L) == LabelMap.end() && "label already in map");
- LabelMap[ L ] = LabelBlock;
-
- // 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 already processed the substatement) there is no
- // extra control-flow to worry about.
- LabelBlock->setLabel(L);
- if (!FinishBlock(LabelBlock))
- return 0;
-
- // 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 = LabelBlock;
-
- return LabelBlock;
-}
-
-CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
- // Goto is a control-flow statement. Thus we stop processing the
- // current block and create a new one.
- if (Block) FinishBlock(Block);
- Block = createBlock(false);
- Block->setTerminator(G);
-
- // If we already know the mapping to the label block add the
- // successor now.
- LabelMapTy::iterator I = LabelMap.find(G->getLabel());
-
- if (I == LabelMap.end())
- // We will need to backpatch this block later.
- BackpatchBlocks.push_back(Block);
- else
- Block->addSuccessor(I->second);
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
- // "for" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(F);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- if (Stmt* C = F->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Now create the loop body.
- {
- assert (F->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);
-
- // Create a new block to contain the (bottom) of the loop body.
- Block = NULL;
-
- if (Stmt* I = F->getInc()) {
- // Generate increment code in its own basic block. This is the target
- // of continue statements.
- Succ = Visit(I);
- }
- else {
- // 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);
- if (!FinishBlock(Block))
- return 0;
- 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;
-
- // Now populate the body block, and in the process create new blocks
- // as we walk the body of the loop.
- CFGBlock* BodyBlock = Visit(F->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // If the loop contains initialization, create a new block for those
- // statements. This block can also contain statements that precede
- // the loop.
- if (Stmt* I = F->getInit()) {
- Block = createBlock();
- return addStmt(I);
- }
- else {
- // There is no loop initialization. We are thus basically a while
- // loop. NULL out Block to force lazy block construction.
- Block = NULL;
- Succ = EntryConditionBlock;
- return EntryConditionBlock;
- }
-}
-
-CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
- // Objective-C fast enumeration 'for' statements:
- // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
- //
- // for ( Type newVariable in collection_expression ) { statements }
- //
- // becomes:
- //
- // prologue:
- // 1. collection_expression
- // T. jump to loop_entry
- // loop_entry:
- // 1. side-effects of element expression
- // 1. ObjCForCollectionStmt [performs binding to newVariable]
- // T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil]
- // TB:
- // statements
- // T. jump to loop_entry
- // FB:
- // what comes after
- //
- // and
- //
- // Type existingItem;
- // for ( existingItem in expression ) { statements }
- //
- // becomes:
- //
- // the same with newVariable replaced with existingItem; the binding
- // works the same except that for one ObjCForCollectionStmt::getElement()
- // returns a DeclStmt and the other returns a DeclRefExpr.
- //
-
- CFGBlock* LoopSuccessor = 0;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- Block = 0;
- }
- else LoopSuccessor = Succ;
-
- // Build the condition blocks.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(S);
-
- // 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);
- Block = ExitConditionBlock;
-
- // Walk the 'element' expression to see if there are any side-effects. We
- // generate new blocks as necesary. We DON'T add the statement by default
- // to the CFG unless it contains control-flow.
- EntryConditionBlock = WalkAST(S->getElement(), false);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- Block = 0;
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // 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);
-
- BreakTargetBlock = LoopSuccessor;
- ContinueTargetBlock = EntryConditionBlock;
-
- CFGBlock* BodyBlock = Visit(S->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // Now create a prologue block to contain the collection expression.
- Block = createBlock();
- return addStmt(S->getCollection());
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
- // FIXME: Add locking 'primitives' to CFG for @synchronized.
-
- // Inline the body.
- CFGBlock *SyncBlock = Visit(S->getSynchBody());
-
- // The sync body starts its own basic block. This makes it a little easier
- // for diagnostic clients.
- if (SyncBlock) {
- if (!FinishBlock(SyncBlock))
- return 0;
-
- Block = 0;
- }
-
- Succ = SyncBlock;
-
- // Inline the sync expression.
- return Visit(S->getSynchExpr());
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
- return NYS();
-}
-
-CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
- // "while" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(W);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- // Thus we update "Succ" after adding the condition.
- if (Stmt* C = W->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- assert(Block == EntryConditionBlock);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Process the loop body.
- {
- 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);
-
- // Create an empty block to represent the transition block for looping
- // back to the head of the loop.
- Block = 0;
- assert(Succ == EntryConditionBlock);
- Succ = createBlock();
- Succ->setLoopTarget(W);
- ContinueTargetBlock = Succ;
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
-
- // Create the body. The returned block is the entry to the loop body.
- CFGBlock* BodyBlock = Visit(W->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "while(...) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-