From: Ted Kremenek Date: Wed, 29 Aug 2007 23:20:49 +0000 (+0000) Subject: Added an (optional) explicit "Label" statement to CFGBlock. If a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9cffe7366ea3beb33c2d58f43a8c3a04c1873e11;p=clang Added an (optional) explicit "Label" statement to CFGBlock. If a block begins with a label or case statement, CFGBlock::getLabel() will return the corresponding LabelStmt/CaseStmt/DefaultStmt. LabelStmts and SwitchCases no longer appear within the "executable" statements of a CFGBlock. More cleanups on visualization/pretty-printing of CFGs (less verbose). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41585 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/CFG.cpp b/AST/CFG.cpp index 2d6e240943..6e2e4dbe0e 100644 --- a/AST/CFG.cpp +++ b/AST/CFG.cpp @@ -462,11 +462,10 @@ CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { LabelMap[ L ] = LabelBlock; // Labels partition blocks, so this is the end of the basic block - // we were processing (the label is the first statement). Add the label - // the to end (really the beginning) of the block. Because this is + // 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->appendStmt(L); + LabelBlock->setLabel(L); FinishBlock(LabelBlock); // We set Block to NULL to allow lazy creation of a new block @@ -808,9 +807,9 @@ CFGBlock* CFGBuilder::VisitSwitchCase(SwitchCase* S) { 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); + // Cases/Default statements partition block, so this is the top of + // the basic block we were processing (the case/default is the label). + CaseBlock->setLabel(S); FinishBlock(CaseBlock); // Add this block to the list of successors for the block with the @@ -898,8 +897,6 @@ void CFG::print(std::ostream& OS) const { // Print the exit block. getExit().print(OS,this); - - OS << "\n"; } namespace { @@ -959,7 +956,7 @@ void CFGBlock::dump(const CFG* cfg) const { print(std::cerr,cfg); } /// print - A simple pretty printer of a CFGBlock that outputs to an ostream. /// Generally this will only be called from CFG::print. -void CFGBlock::print(std::ostream& OS, const CFG* cfg) const { +void CFGBlock::print(std::ostream& OS, const CFG* cfg, bool print_edges) const { // Print the header. OS << "\n [ B" << getBlockID(); @@ -970,53 +967,69 @@ void CFGBlock::print(std::ostream& OS, const CFG* cfg) const { } else OS << " ]\n"; + // Print the label of this block. + if (Stmt* S = const_cast(getLabel())) { + if (print_edges) OS << " "; + if (LabelStmt* L = dyn_cast(S)) + OS << L->getName(); + else if (CaseStmt* C = dyn_cast(S)) { + OS << "case "; + C->getLHS()->printPretty(OS); + if (C->getRHS()) { + OS << " ... "; + C->getRHS()->printPretty(OS); + } + } + else if (DefaultStmt* D = dyn_cast(D)) { + OS << "default"; + } + else assert(false && "Invalid label statement in CFGBlock."); + + OS << ":\n"; + } + // Iterate through the statements in the block and print them. - OS << " ------------------------\n"; unsigned j = 1; for (const_iterator I = Stmts.begin(), E = Stmts.end() ; I != E ; ++I, ++j ) { - // Print the statement # in the basic block. - OS << " " << std::setw(3) << j << ": "; - - // Print the statement/expression. - Stmt* S = *I; - - if (LabelStmt* L = dyn_cast(S)) - OS << L->getName() << ": (LABEL)\n"; - else - (*I)->printPretty(OS); - + // Print the statement # in the basic block and the statement itself. + if (print_edges) OS << " "; + OS << std::setw(3) << j << ": "; + (*I)->printPretty(OS); + // Expressions need a newline. if (isa(*I)) OS << '\n'; } - OS << " ------------------------\n"; - - // Print the predecessors of this block. - OS << " Predecessors (" << pred_size() << "):"; - unsigned i = 0; - for (const_pred_iterator I = pred_begin(), E = pred_end(); I != E; ++I, ++i) { - if (i == 8 || (i-8) == 0) { - OS << "\n "; - } - OS << " B" << (*I)->getBlockID(); + + // Print the terminator of this block. + if (getTerminator()) { + if (print_edges) OS << " "; + OS << " T: "; + CFGBlockTerminatorPrint(OS).Visit(const_cast(getTerminator())); } - // Print the terminator of this block. - OS << "\n Terminator: "; - if (ControlFlowStmt) - CFGBlockTerminatorPrint(OS).Visit(ControlFlowStmt); - else - OS << "\n"; - - // Print the successors of this block. - OS << " Successors (" << succ_size() << "):"; - i = 0; - for (const_succ_iterator I = succ_begin(), E = succ_end(); I != E; ++I, ++i) { - if (i == 8 || (i-8) % 10 == 0) { - OS << "\n "; + if (print_edges) { + // Print the predecessors of this block. + OS << " Predecessors (" << pred_size() << "):"; + unsigned i = 0; + for (const_pred_iterator I = pred_begin(), E = pred_end(); I != E; ++I, ++i) { + if (i == 8 || (i-8) == 0) { + OS << "\n "; + } + OS << " B" << (*I)->getBlockID(); + } + OS << '\n'; + + // Print the successors of this block. + OS << " Successors (" << succ_size() << "):"; + i = 0; + for (const_succ_iterator I = succ_begin(), E = succ_end(); I != E; ++I, ++i) { + if (i == 8 || (i-8) % 10 == 0) { + OS << "\n "; + } + OS << " B" << (*I)->getBlockID(); } - OS << " B" << (*I)->getBlockID(); + OS << '\n'; } - OS << '\n'; } //===----------------------------------------------------------------------===// @@ -1029,7 +1042,7 @@ struct DOTGraphTraits : public DefaultDOTGraphTraits { static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { std::ostringstream Out; - Node->print(Out,Graph); + Node->print(Out,Graph,false); std::string OutStr = Out.str(); if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h index 18157d1363..460e23cdfc 100644 --- a/include/clang/AST/CFG.h +++ b/include/clang/AST/CFG.h @@ -43,15 +43,24 @@ class CFG; /// Terminator Successor Ordering /// ----------------------------------------------------- /// if Then Block; Else Block +/// ? operator LHS expression; RHS expression +/// &&, || expression that uses result of && or ||, RHS /// class CFGBlock { typedef std::vector StatementListTy; /// Stmts - The set of statements in the basic block. StatementListTy Stmts; - /// ControlFlowStmt - The terminator for a basic block that + + /// 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; + + /// Terminator - The terminator for a basic block that /// indicates the type of control-flow that occurs between a block /// and its successors. - Stmt* ControlFlowStmt; + Stmt* Terminator; + /// BlockID - A numerical ID assigned to a CFGBlock during construction /// of the CFG. unsigned BlockID; @@ -63,7 +72,7 @@ class CFGBlock { AdjacentBlocks Succs; public: - explicit CFGBlock(unsigned blockid) : ControlFlowStmt(NULL), + explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL), BlockID(blockid) {} ~CFGBlock() {}; @@ -129,8 +138,14 @@ public: // Manipulation of block contents void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); } - void setTerminator(Stmt* Statement) { ControlFlowStmt = Statement; } - Stmt* getTerminator() { return ControlFlowStmt; } + void setTerminator(Stmt* Statement) { Terminator = Statement; } + void setLabel(Stmt* Statement) { Label = Statement; } + + Stmt* getTerminator() { return Terminator; } + const Stmt* getTerminator() const { return Terminator; } + + Stmt* getLabel() { return Label; } + const Stmt* getLabel() const { return Label; } void reverseStmts(); @@ -142,7 +157,7 @@ public: unsigned getBlockID() const { return BlockID; } void dump(const CFG* cfg) const; - void print(std::ostream& OS, const CFG* cfg) const; + void print(std::ostream& OS, const CFG* cfg, bool print_edges = true) const; };