//
// The LLVM Compiler Infrastructure
//
-// This file was developed by the LLVM research group and is distributed under
-// the University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
-// This file defines a '-print-cfg' analysis pass, which emits the
+// This file defines a '-dot-cfg' analysis pass, which emits the
// cfg.<fnname>.dot file for each function in the program, with a graph of the
// CFG for that function.
//
//
//===----------------------------------------------------------------------===//
-#include "llvm/Function.h"
-#include "llvm/Instructions.h"
-#include "llvm/Pass.h"
#include "llvm/Analysis/CFGPrinter.h"
-#include "llvm/Assembly/Writer.h"
-#include "llvm/Support/CFG.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Config/config.h"
-#include <iosfwd>
-#include <sstream>
-#include <fstream>
+#include "llvm/Pass.h"
+#include "llvm/Support/FileSystem.h"
using namespace llvm;
-/// CFGOnly flag - This is used to control whether or not the CFG graph printer
-/// prints out the contents of basic blocks or not. This is acceptable because
-/// this code is only really used for debugging purposes.
-///
-static bool CFGOnly = false;
-
-namespace llvm {
-template<>
-struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits {
- static std::string getGraphName(const Function *F) {
- return "CFG for '" + F->getName() + "' function";
- }
-
- static std::string getNodeLabel(const BasicBlock *Node,
- const Function *Graph) {
- if (CFGOnly && !Node->getName().empty())
- return Node->getName() + ":";
-
- std::ostringstream Out;
- if (CFGOnly) {
- WriteAsOperand(Out, Node, false);
- return Out.str();
+namespace {
+ struct CFGViewer : public FunctionPass {
+ static char ID; // Pass identifcation, replacement for typeid
+ CFGViewer() : FunctionPass(ID) {
+ initializeCFGOnlyViewerPass(*PassRegistry::getPassRegistry());
}
- if (Node->getName().empty()) {
- WriteAsOperand(Out, Node, false);
- Out << ":";
+ bool runOnFunction(Function &F) override {
+ F.viewCFG();
+ return false;
}
- Out << *Node;
- std::string OutStr = Out.str();
- if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
-
- // Process string output to make it nicer...
- for (unsigned i = 0; i != OutStr.length(); ++i)
- if (OutStr[i] == '\n') { // Left justify
- OutStr[i] = '\\';
- OutStr.insert(OutStr.begin()+i+1, 'l');
- } else if (OutStr[i] == ';') { // Delete comments!
- unsigned Idx = OutStr.find('\n', i+1); // Find end of line
- OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx);
- --i;
- }
-
- return OutStr;
- }
-
- static std::string getEdgeSourceLabel(const BasicBlock *Node,
- succ_const_iterator I) {
- // Label source of conditional branches with "T" or "F"
- if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator()))
- if (BI->isConditional())
- return (I == succ_begin(Node)) ? "T" : "F";
- return "";
- }
-};
+ void print(raw_ostream &OS, const Module* = nullptr) const override {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+ };
}
+char CFGViewer::ID = 0;
+INITIALIZE_PASS(CFGViewer, "view-cfg", "View CFG of function", false, true)
+
+namespace {
+ struct CFGOnlyViewer : public FunctionPass {
+ static char ID; // Pass identifcation, replacement for typeid
+ CFGOnlyViewer() : FunctionPass(ID) {
+ initializeCFGOnlyViewerPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ F.viewCFGOnly();
+ return false;
+ }
+
+ void print(raw_ostream &OS, const Module* = nullptr) const override {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+ };
+}
+
+char CFGOnlyViewer::ID = 0;
+INITIALIZE_PASS(CFGOnlyViewer, "view-cfg-only",
+ "View CFG of function (with no function bodies)", false, true)
+
namespace {
struct CFGPrinter : public FunctionPass {
- virtual bool runOnFunction(Function &F) {
- std::string Filename = "cfg." + F.getName() + ".dot";
- llvm_cerr << "Writing '" << Filename << "'...";
- std::ofstream File(Filename.c_str());
+ static char ID; // Pass identification, replacement for typeid
+ CFGPrinter() : FunctionPass(ID) {
+ initializeCFGPrinterPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ std::string Filename = "cfg." + F.getName().str() + ".dot";
+ errs() << "Writing '" << Filename << "'...";
- if (File.good())
+ std::error_code EC;
+ raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
+
+ if (!EC)
WriteGraph(File, (const Function*)&F);
else
- llvm_cerr << " error opening file for writing!";
- llvm_cerr << "\n";
+ errs() << " error opening file for writing!";
+ errs() << "\n";
return false;
}
- void print(std::ostream &OS, const Module* = 0) const {}
+ void print(raw_ostream &OS, const Module* = nullptr) const override {}
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
};
+}
- RegisterPass<CFGPrinter> P1("print-cfg",
- "Print CFG of function to 'dot' file");
+char CFGPrinter::ID = 0;
+INITIALIZE_PASS(CFGPrinter, "dot-cfg", "Print CFG of function to 'dot' file",
+ false, true)
- struct CFGOnlyPrinter : public CFGPrinter {
- virtual bool runOnFunction(Function &F) {
- bool OldCFGOnly = CFGOnly;
- CFGOnly = true;
- CFGPrinter::runOnFunction(F);
- CFGOnly = OldCFGOnly;
+namespace {
+ struct CFGOnlyPrinter : public FunctionPass {
+ static char ID; // Pass identification, replacement for typeid
+ CFGOnlyPrinter() : FunctionPass(ID) {
+ initializeCFGOnlyPrinterPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ std::string Filename = "cfg." + F.getName().str() + ".dot";
+ errs() << "Writing '" << Filename << "'...";
+
+ std::error_code EC;
+ raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
+
+ if (!EC)
+ WriteGraph(File, (const Function*)&F, true);
+ else
+ errs() << " error opening file for writing!";
+ errs() << "\n";
return false;
}
- void print(std::ostream &OS, const Module* = 0) const {}
+ void print(raw_ostream &OS, const Module* = nullptr) const override {}
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
};
-
- RegisterPass<CFGOnlyPrinter>
- P2("print-cfg-only",
- "Print CFG of function to 'dot' file (with no function bodies)");
}
+char CFGOnlyPrinter::ID = 0;
+INITIALIZE_PASS(CFGOnlyPrinter, "dot-cfg-only",
+ "Print CFG of function to 'dot' file (with no function bodies)",
+ false, true)
+
/// viewCFG - This function is meant for use from the debugger. You can just
/// say 'call F->viewCFG()' and a ghostview window should pop up from the
/// program, displaying the CFG of the current function. This depends on there
/// viewCFGOnly - This function is meant for use from the debugger. It works
/// just like viewCFG, but it does not include the contents of basic blocks
-/// into the nodes, just the label. If you are only interested in the CFG t
-/// his can make the graph smaller.
+/// into the nodes, just the label. If you are only interested in the CFG
+/// this can make the graph smaller.
///
void Function::viewCFGOnly() const {
- CFGOnly = true;
- viewCFG();
- CFGOnly = false;
+ ViewGraph(this, "cfg" + getName(), true);
}
FunctionPass *llvm::createCFGPrinterPass () {