diff options
-rw-r--r-- | AST/CFG.cpp | 251 | ||||
-rw-r--r-- | AST/StmtPrinter.cpp | 22 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 3 | ||||
-rw-r--r-- | include/clang/AST/CFG.h | 7 | ||||
-rw-r--r-- | include/clang/AST/PrettyPrinter.h | 31 | ||||
-rw-r--r-- | include/clang/AST/Stmt.h | 5 |
6 files changed, 231 insertions, 88 deletions
diff --git a/AST/CFG.cpp b/AST/CFG.cpp index 89d7af9965..512c69ec5b 100644 --- a/AST/CFG.cpp +++ b/AST/CFG.cpp @@ -15,6 +15,7 @@ #include "clang/AST/CFG.h" #include "clang/AST/Expr.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" @@ -921,48 +922,65 @@ void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); } // CFG pretty printing //===----------------------------------------------------------------------===// -/// dump - A simple pretty printer of a CFG that outputs to stderr. -void CFG::dump() const { print(std::cerr); } - -/// print - A simple pretty printer of a CFG that outputs to an ostream. -void CFG::print(std::ostream& OS) const { - - // Print the entry block. - getEntry().print(OS,this); +namespace { - // Iterate through the CFGBlocks and print them one by one. - for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { - // Skip the entry block, because we already printed it. - if (&(*I) == &getEntry() || &(*I) == &getExit()) continue; - I->print(OS,this); +class StmtPrinterHelper : public PrinterHelper { + typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; + StmtMapTy StmtMap; + signed CurrentBlock; + unsigned CurrentStmt; +public: + StmtPrinterHelper(const CFG* cfg) : CurrentBlock(0), CurrentStmt(0) { + for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { + unsigned j = 1; + for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ; + BI != BEnd; ++BI, ++j ) + StmtMap[*BI] = std::make_pair(I->getBlockID(),j); + } } + + virtual ~StmtPrinterHelper() {} - // Print the exit block. - getExit().print(OS,this); -} + void setBlockID(signed i) { CurrentBlock = i; } + void setStmtID(unsigned i) { CurrentStmt = i; } + + virtual bool handledStmt(Stmt* E, std::ostream& OS) { + StmtMapTy::iterator I = StmtMap.find(E); -namespace { + if (I == StmtMap.end()) + return false; + + if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock + && I->second.second == CurrentStmt) + return false; + + OS << "[B" << I->second.first << "." << I->second.second << "]"; + return true; + } +}; class CFGBlockTerminatorPrint : public StmtVisitor<CFGBlockTerminatorPrint, - void > { +void > { std::ostream& OS; + StmtPrinterHelper* Helper; public: - CFGBlockTerminatorPrint(std::ostream& os) : OS(os) {} + CFGBlockTerminatorPrint(std::ostream& os, StmtPrinterHelper* helper) + : OS(os), Helper(helper) {} void VisitIfStmt(IfStmt* I) { OS << "if "; - I->getCond()->printPretty(OS); + I->getCond()->printPretty(OS,Helper); OS << "\n"; } // Default case. - void VisitStmt(Stmt* S) { S->printPretty(OS); } + void VisitStmt(Stmt* S) { S->printPretty(OS,Helper); } void VisitForStmt(ForStmt* F) { OS << "for (" ; if (F->getInit()) OS << "..."; OS << "; "; - if (Stmt* C = F->getCond()) C->printPretty(OS); + if (Stmt* C = F->getCond()) C->printPretty(OS,Helper); OS << "; "; if (F->getInc()) OS << "..."; OS << ")\n"; @@ -970,48 +988,52 @@ public: void VisitWhileStmt(WhileStmt* W) { OS << "while " ; - if (Stmt* C = W->getCond()) C->printPretty(OS); + if (Stmt* C = W->getCond()) C->printPretty(OS,Helper); OS << "\n"; } void VisitDoStmt(DoStmt* D) { OS << "do ... while "; - if (Stmt* C = D->getCond()) C->printPretty(OS); + if (Stmt* C = D->getCond()) C->printPretty(OS,Helper); OS << '\n'; } - + void VisitSwitchStmt(SwitchStmt* S) { OS << "switch "; - S->getCond()->printPretty(OS); + S->getCond()->printPretty(OS,Helper); OS << '\n'; } void VisitExpr(Expr* E) { - E->printPretty(OS); + E->printPretty(OS,Helper); OS << '\n'; } }; -} // end anonymous namespace - -/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. -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, bool print_edges) const { - + + +void print_block(std::ostream& OS, const CFG* cfg, const CFGBlock& B, + StmtPrinterHelper* Helper, bool print_edges) { + + if (Helper) Helper->setBlockID(B.getBlockID()); + // Print the header. - OS << "\n [ B" << getBlockID(); - if (this == &cfg->getEntry()) { OS << " (ENTRY) ]\n"; } - else if (this == &cfg->getExit()) { OS << " (EXIT) ]\n"; } - else if (this == cfg->getIndirectGotoBlock()) { + OS << "\n [ B" << B.getBlockID(); + + if (&B == &cfg->getEntry()) + OS << " (ENTRY) ]\n"; + else if (&B == &cfg->getExit()) + OS << " (EXIT) ]\n"; + else if (&B == cfg->getIndirectGotoBlock()) OS << " (INDIRECT GOTO DISPATCH) ]\n"; - } - else OS << " ]\n"; - + else + OS << " ]\n"; + // Print the label of this block. - if (Stmt* S = const_cast<Stmt*>(getLabel())) { - if (print_edges) OS << " "; + if (Stmt* S = const_cast<Stmt*>(B.getLabel())) { + + if (print_edges) + OS << " "; + if (LabelStmt* L = dyn_cast<LabelStmt>(S)) OS << L->getName(); else if (CaseStmt* C = dyn_cast<CaseStmt>(S)) { @@ -1021,70 +1043,148 @@ void CFGBlock::print(std::ostream& OS, const CFG* cfg, bool print_edges) const { OS << " ... "; C->getRHS()->printPretty(OS); } - } - else if (DefaultStmt* D = dyn_cast<DefaultStmt>(D)) { + } + else if (DefaultStmt* D = dyn_cast<DefaultStmt>(D)) OS << "default"; - } - else assert(false && "Invalid label statement in CFGBlock."); - + else + assert(false && "Invalid label statement in CFGBlock."); + OS << ":\n"; } - + // Iterate through the statements in the block and print them. unsigned j = 1; - for (const_iterator I = Stmts.begin(), E = Stmts.end() ; I != E ; ++I, ++j ) { + + for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; + I != E ; ++I, ++j ) { + // Print the statement # in the basic block and the statement itself. - if (print_edges) OS << " "; - OS << std::setw(3) << j << ": "; - (*I)->printPretty(OS); - + if (print_edges) + OS << " "; + + OS << std::setw(3) << j << ": "; + + if (Helper) + Helper->setStmtID(j); + + (*I)->printPretty(OS, Helper); + // Expressions need a newline. if (isa<Expr>(*I)) OS << '\n'; } - + // Print the terminator of this block. - if (getTerminator()) { - if (print_edges) OS << " "; + if (B.getTerminator()) { + if (print_edges) + OS << " "; + OS << " T: "; - CFGBlockTerminatorPrint(OS).Visit(const_cast<Stmt*>(getTerminator())); + + if (Helper) Helper->setBlockID(-1); + + CFGBlockTerminatorPrint TPrinter(OS,Helper); + TPrinter.Visit(const_cast<Stmt*>(B.getTerminator())); } - + if (print_edges) { // Print the predecessors of this block. - OS << " Predecessors (" << pred_size() << "):"; + OS << " Predecessors (" << B.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) { + + for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.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() << "):"; + OS << " Successors (" << B.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) { + + for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) % 10 == 0) OS << "\n "; - } + OS << " B" << (*I)->getBlockID(); } + OS << '\n'; } +} + +} // end anonymous namespace + +/// dump - A simple pretty printer of a CFG that outputs to stderr. +void CFG::dump() const { print(std::cerr); } + +/// print - A simple pretty printer of a CFG that outputs to an ostream. +void CFG::print(std::ostream& OS) const { + + StmtPrinterHelper Helper(this); + + // Print the entry block. + print_block(OS, this, getEntry(), &Helper, true); + + // Iterate through the CFGBlocks and print them one by one. + for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { + // Skip the entry block, because we already printed it. + if (&(*I) == &getEntry() || &(*I) == &getExit()) + continue; + + print_block(OS, this, *I, &Helper, true); + } + + // Print the exit block. + print_block(OS, this, getExit(), &Helper, true); +} + +/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. +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 { + StmtPrinterHelper Helper(cfg); + print_block(OS, cfg, *this, &Helper, true); } //===----------------------------------------------------------------------===// // CFG Graphviz Visualization //===----------------------------------------------------------------------===// + +#ifndef NDEBUG +namespace { + StmtPrinterHelper* GraphHelper; +} +#endif + +void CFG::viewCFG() const { +#ifndef NDEBUG + StmtPrinterHelper H(this); + GraphHelper = &H; + llvm::ViewGraph(this,"CFG"); + GraphHelper = NULL; +#else + std::cerr << "CFG::viewCFG is only available in debug builds on " + << "systems with Graphviz or gv!" << std::endl; +#endif +} + namespace llvm { template<> struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { std::ostringstream Out; - Node->print(Out,Graph,false); + print_block(Out,Graph, *Node, GraphHelper, false); std::string OutStr = Out.str(); if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); @@ -1100,12 +1200,3 @@ struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { } }; } // end namespace llvm - -void CFG::viewCFG() const { -#ifndef NDEBUG - llvm::ViewGraph(this,"CFG"); -#else - std::cerr << "CFG::viewCFG is only available in debug builds on " - << "systems with Graphviz or gv!" << std::endl; -#endif -} diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index 6903080422..28bf446e0b 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -15,6 +15,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyPrinter.h" #include "clang/Lex/IdentifierTable.h" #include "llvm/Support/Compiler.h" #include <iostream> @@ -29,8 +30,10 @@ namespace { class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> { std::ostream &OS; unsigned IndentLevel; + clang::PrinterHelper* Helper; public: - StmtPrinter(std::ostream &os) : OS(os), IndentLevel(0) {} + StmtPrinter(std::ostream &os, PrinterHelper* helper) : + OS(os), IndentLevel(0), Helper(helper) {} void PrintStmt(Stmt *S, int SubIndent = 1) { IndentLevel += SubIndent; @@ -67,6 +70,12 @@ namespace { bool PrintOffsetOfDesignator(Expr *E); void VisitUnaryOffsetOf(UnaryOperator *Node); + void Visit(Stmt* S) { + if (Helper && Helper->handledStmt(S,OS)) + return; + else StmtVisitor<StmtPrinter>::Visit(S); + } + void VisitStmt(Stmt *Node); #define STMT(N, CLASS, PARENT) \ void Visit##CLASS(CLASS *Node); @@ -593,12 +602,19 @@ void Stmt::dumpPretty() const { printPretty(std::cerr); } -void Stmt::printPretty(std::ostream &OS) const { +void Stmt::printPretty(std::ostream &OS, PrinterHelper* Helper) const { if (this == 0) { OS << "<NULL>"; return; } - StmtPrinter P(OS); + StmtPrinter P(OS, Helper); P.Visit(const_cast<Stmt*>(this)); } + +//===----------------------------------------------------------------------===// +// PrinterHelper +//===----------------------------------------------------------------------===// + +// Implement virtual destructor. +PrinterHelper::~PrinterHelper() {}
\ No newline at end of file diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index cb6a73d08b..4beeaef7a6 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -208,6 +208,7 @@ 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; }; 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; }; 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = "<group>"; }; + 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = "<group>"; }; 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -503,6 +504,7 @@ DE0FCA620A95859D00248FD5 /* Expr.h */, 1A30A9E80B93A4C800201A91 /* ExprCXX.h */, DE6951C60C4D1F5D00A5826B /* RecordLayout.h */, + 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */, DE3452800AEF1B1800DBC861 /* Stmt.h */, DE345F210AFD347900DBC861 /* StmtNodes.def */, DE345C190AFC658B00DBC861 /* StmtVisitor.h */, @@ -635,6 +637,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/AST/CFG.h b/include/clang/AST/CFG.h index a09d9346e9..591668411b 100644 --- a/include/clang/AST/CFG.h +++ b/include/clang/AST/CFG.h @@ -22,8 +22,9 @@ namespace clang { -class Stmt; -class CFG; + class Stmt; + class CFG; + class PrinterHelper; /// CFGBlock - Represents a single basic block in a source-level CFG. /// It consists of: @@ -160,7 +161,7 @@ public: unsigned getBlockID() const { return BlockID; } void dump(const CFG* cfg) const; - void print(std::ostream& OS, const CFG* cfg, bool print_edges = true) const; + void print(std::ostream& OS, const CFG* cfg) const; }; diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h new file mode 100644 index 0000000000..434110e737 --- /dev/null +++ b/include/clang/AST/PrettyPrinter.h @@ -0,0 +1,31 @@ +//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Ted Kremenek and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PrinterHelper interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H +#define LLVM_CLANG_AST_PRETTY_PRINTER_H + +#include <iosfwd> + +namespace clang { + +class Stmt; + +class PrinterHelper { +public: + virtual ~PrinterHelper(); + virtual bool handledStmt(Stmt* E, std::ostream& OS) = 0; +}; + +} // end namespace clang + +#endif
\ No newline at end of file diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 025be37b95..de430a9193 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -25,7 +25,8 @@ namespace clang { class IdentifierInfo; class SourceManager; class SwitchStmt; - + class PrinterHelper; + /// Stmt - This represents one statement. /// class Stmt { @@ -67,7 +68,7 @@ public: /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST /// back to its original source language syntax. void dumpPretty() const; - void printPretty(std::ostream &OS) const; + void printPretty(std::ostream &OS, PrinterHelper* = NULL) const; // Implement isa<T> support. static bool classof(const Stmt *) { return true; } |