forked from OSchip/llvm-project
No functionality change. Moved visitor methods for CFGBuilder out-of-line
from the class declaration. This enables a nice view of what visitor methods have been implemented. llvm-svn: 41337
This commit is contained in:
parent
1aaab49a3e
commit
9aae513318
|
@ -75,12 +75,39 @@ public:
|
|||
|
||||
~CFGBuilder() { delete cfg; }
|
||||
|
||||
/// 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* buildCFG(Stmt* Statement) {
|
||||
// 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* VisitStmt(Stmt* Statement);
|
||||
CFGBlock* VisitNullStmt(NullStmt* Statement);
|
||||
CFGBlock* VisitCompoundStmt(CompoundStmt* C);
|
||||
CFGBlock* VisitIfStmt(IfStmt* I);
|
||||
CFGBlock* VisitReturnStmt(ReturnStmt* R);
|
||||
CFGBlock* VisitLabelStmt(LabelStmt* L);
|
||||
CFGBlock* VisitGotoStmt(GotoStmt* G);
|
||||
CFGBlock* VisitForStmt(ForStmt* F);
|
||||
CFGBlock* VisitWhileStmt(WhileStmt* W);
|
||||
CFGBlock* VisitDoStmt(DoStmt* D);
|
||||
CFGBlock* VisitContinueStmt(ContinueStmt* C);
|
||||
CFGBlock* VisitBreakStmt(BreakStmt* B);
|
||||
CFGBlock* VisitSwitchStmt(SwitchStmt* S);
|
||||
CFGBlock* VisitSwitchCase(SwitchCase* S);
|
||||
|
||||
private:
|
||||
CFGBlock* createBlock(bool add_successor = true);
|
||||
void FinishBlock(CFGBlock* B);
|
||||
|
||||
};
|
||||
|
||||
/// 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) {
|
||||
if (!Statement) return NULL;
|
||||
|
||||
// Create an empty block that will serve as the exit block for the CFG.
|
||||
|
@ -118,24 +145,24 @@ public:
|
|||
return t;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// createBlock - Used to lazily create blocks that are connected
|
||||
// to the current (global) succcessor.
|
||||
CFGBlock* createBlock( bool add_successor = true ) {
|
||||
/// createBlock - Used to lazily create blocks that are connected
|
||||
/// to the current (global) succcessor.
|
||||
CFGBlock* CFGBuilder::createBlock(bool add_successor) {
|
||||
CFGBlock* B = cfg->createBlock(NumBlocks++);
|
||||
if (add_successor && Succ) B->addSuccessor(Succ);
|
||||
return B;
|
||||
}
|
||||
}
|
||||
|
||||
// FinishBlock - When the last statement has been added to the block,
|
||||
// usually we must reverse the statements because they have been inserted
|
||||
// in reverse order. When processing labels, however, there are cases
|
||||
// in the recursion where we may have already reversed the statements
|
||||
// in a block. This method safely tidies up a block: if the block
|
||||
// has a label at the front, it has already been reversed. Otherwise,
|
||||
// we reverse it.
|
||||
void FinishBlock(CFGBlock* B) {
|
||||
/// FinishBlock - When the last statement has been added to the block,
|
||||
/// usually we must reverse the statements because they have been inserted
|
||||
/// in reverse order. When processing labels, however, there are cases
|
||||
/// in the recursion where we may have already reversed the statements
|
||||
/// in a block. This method safely tidies up a block: if the block
|
||||
/// has a label at the front, it has already been reversed. Otherwise,
|
||||
/// we reverse it.
|
||||
void CFGBuilder::FinishBlock(CFGBlock* B) {
|
||||
assert (B);
|
||||
CFGBlock::iterator I = B->begin();
|
||||
if (I != B->end()) {
|
||||
|
@ -146,10 +173,10 @@ public:
|
|||
|
||||
B->reverseStmts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Here we handle statements with no branching control flow.
|
||||
CFGBlock* VisitStmt(Stmt* Statement) {
|
||||
/// 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.
|
||||
|
@ -161,13 +188,13 @@ public:
|
|||
Block->appendStmt(Statement);
|
||||
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitNullStmt(NullStmt* Statement) {
|
||||
CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) {
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitCompoundStmt(CompoundStmt* C) {
|
||||
CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
|
||||
// The value returned from this function is the last created CFGBlock
|
||||
// that represents the "entry" point for the translated AST node.
|
||||
CFGBlock* LastBlock;
|
||||
|
@ -179,10 +206,9 @@ public:
|
|||
return NULL;
|
||||
|
||||
return LastBlock;
|
||||
}
|
||||
|
||||
CFGBlock* VisitIfStmt(IfStmt* I) {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -242,9 +268,9 @@ public:
|
|||
Block->addSuccessor(ElseBlock);
|
||||
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitReturnStmt(ReturnStmt* R) {
|
||||
CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
|
||||
// If we were in the middle of a block we stop processing that block
|
||||
// and reverse its statements.
|
||||
//
|
||||
|
@ -268,9 +294,9 @@ public:
|
|||
Block->setTerminator(R);
|
||||
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitLabelStmt(LabelStmt* L) {
|
||||
CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
|
||||
// Get the block of the labeled statement. Add it to our map.
|
||||
CFGBlock* LabelBlock = Visit(L->getSubStmt());
|
||||
assert (LabelBlock);
|
||||
|
@ -291,9 +317,9 @@ public:
|
|||
Succ = LabelBlock;
|
||||
|
||||
return LabelBlock;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitGotoStmt(GotoStmt* G) {
|
||||
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);
|
||||
|
@ -311,9 +337,9 @@ public:
|
|||
Block->addSuccessor(I->second);
|
||||
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitForStmt(ForStmt* F) {
|
||||
CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
|
||||
// "for" is a control-flow statement. Thus we stop processing the
|
||||
// current block.
|
||||
|
||||
|
@ -383,9 +409,9 @@ public:
|
|||
Block = NULL;
|
||||
return ConditionBlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitWhileStmt(WhileStmt* W) {
|
||||
CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
|
||||
// "while" is a control-flow statement. Thus we stop processing the
|
||||
// current block.
|
||||
|
||||
|
@ -444,9 +470,9 @@ public:
|
|||
|
||||
// Return the condition block, which is the dominating block for the loop.
|
||||
return ConditionBlock;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitDoStmt(DoStmt* D) {
|
||||
CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) {
|
||||
// "do...while" is a control-flow statement. Thus we stop processing the
|
||||
// current block.
|
||||
|
||||
|
@ -505,9 +531,9 @@ public:
|
|||
|
||||
// Return the loop body, which is the dominating block for the loop.
|
||||
return BodyBlock;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitContinueStmt(ContinueStmt* C) {
|
||||
CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
|
||||
// "continue" is a control-flow statement. Thus we stop processing the
|
||||
// current block.
|
||||
if (Block) FinishBlock(Block);
|
||||
|
@ -521,9 +547,9 @@ public:
|
|||
if (ContinueTargetBlock) Block->addSuccessor(ContinueTargetBlock);
|
||||
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitBreakStmt(BreakStmt* B) {
|
||||
CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) {
|
||||
// "break" is a control-flow statement. Thus we stop processing the
|
||||
// current block.
|
||||
if (Block) FinishBlock(Block);
|
||||
|
@ -537,9 +563,9 @@ public:
|
|||
if (BreakTargetBlock) Block->addSuccessor(BreakTargetBlock);
|
||||
|
||||
return Block;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitSwitchStmt(SwitchStmt* S) {
|
||||
CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* S) {
|
||||
// "switch" is a control-flow statement. Thus we stop processing the
|
||||
// current block.
|
||||
CFGBlock* SwitchSuccessor = NULL;
|
||||
|
@ -578,9 +604,9 @@ public:
|
|||
|
||||
Block = SwitchTerminatedBlock;
|
||||
return SwitchTerminatedBlock;
|
||||
}
|
||||
}
|
||||
|
||||
CFGBlock* VisitSwitchCase(SwitchCase* S) {
|
||||
CFGBlock* CFGBuilder::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.
|
||||
|
@ -603,9 +629,9 @@ public:
|
|||
Succ = CaseBlock;
|
||||
|
||||
return CaseBlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// createBlock - Constructs and adds a new CFGBlock to the CFG. The
|
||||
|
@ -640,7 +666,6 @@ void CFG::dump() { print(std::cerr); }
|
|||
|
||||
/// print - A simple pretty printer of a CFG that outputs to an ostream.
|
||||
void CFG::print(std::ostream& OS) {
|
||||
|
||||
// Print the Entry block.
|
||||
if (begin() != end()) {
|
||||
CFGBlock& Entry = getEntry();
|
||||
|
@ -670,10 +695,10 @@ void CFG::print(std::ostream& OS) {
|
|||
|
||||
namespace {
|
||||
|
||||
class CFGBlockTerminatorPrint : public StmtVisitor<CFGBlockTerminatorPrint,
|
||||
class CFGBlockTerminatorPrint : public StmtVisitor<CFGBlockTerminatorPrint,
|
||||
void > {
|
||||
std::ostream& OS;
|
||||
public:
|
||||
public:
|
||||
CFGBlockTerminatorPrint(std::ostream& os) : OS(os) {}
|
||||
|
||||
void VisitIfStmt(IfStmt* I) {
|
||||
|
@ -706,8 +731,8 @@ namespace {
|
|||
if (Stmt* C = D->getCond()) C->printPretty(OS);
|
||||
OS << "\n";
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
|
||||
void CFGBlock::dump() { print(std::cerr); }
|
||||
|
|
Loading…
Reference in New Issue