aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AST/CFG.cpp251
-rw-r--r--AST/StmtPrinter.cpp22
-rw-r--r--clang.xcodeproj/project.pbxproj3
-rw-r--r--include/clang/AST/CFG.h7
-rw-r--r--include/clang/AST/PrettyPrinter.h31
-rw-r--r--include/clang/AST/Stmt.h5
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; }