diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/CFGPrinter.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Analysis/CFGPrinter.cpp | 200 | 
1 files changed, 200 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/CFGPrinter.cpp b/contrib/llvm-project/llvm/lib/Analysis/CFGPrinter.cpp new file mode 100644 index 000000000000..4f4103fefa25 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Analysis/CFGPrinter.cpp @@ -0,0 +1,200 @@ +//===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a `-dot-cfg` analysis pass, which emits the +// `<prefix>.<fnname>.dot` file for each function in the program, with a graph +// of the CFG for that function. The default value for `<prefix>` is `cfg` but +// can be customized as needed. +// +// The other main feature of this file is that it implements the +// Function::viewCFG method, which is useful for debugging passes which operate +// on the CFG. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/CFGPrinter.h" +#include "llvm/Pass.h" +#include "llvm/Support/FileSystem.h" +using namespace llvm; + +static cl::opt<std::string> CFGFuncName( +    "cfg-func-name", cl::Hidden, +    cl::desc("The name of a function (or its substring)" +             " whose CFG is viewed/printed.")); + +static cl::opt<std::string> CFGDotFilenamePrefix( +    "cfg-dot-filename-prefix", cl::Hidden, +    cl::desc("The prefix used for the CFG dot file names.")); + +namespace { +  struct CFGViewerLegacyPass : public FunctionPass { +    static char ID; // Pass identifcation, replacement for typeid +    CFGViewerLegacyPass() : FunctionPass(ID) { +      initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry()); +    } + +    bool runOnFunction(Function &F) override { +      F.viewCFG(); +      return false; +    } + +    void print(raw_ostream &OS, const Module* = nullptr) const override {} + +    void getAnalysisUsage(AnalysisUsage &AU) const override { +      AU.setPreservesAll(); +    } +  }; +} + +char CFGViewerLegacyPass::ID = 0; +INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true) + +PreservedAnalyses CFGViewerPass::run(Function &F, +                                     FunctionAnalysisManager &AM) { +  F.viewCFG(); +  return PreservedAnalyses::all(); +} + + +namespace { +  struct CFGOnlyViewerLegacyPass : public FunctionPass { +    static char ID; // Pass identifcation, replacement for typeid +    CFGOnlyViewerLegacyPass() : FunctionPass(ID) { +      initializeCFGOnlyViewerLegacyPassPass(*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 CFGOnlyViewerLegacyPass::ID = 0; +INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", +                "View CFG of function (with no function bodies)", false, true) + +PreservedAnalyses CFGOnlyViewerPass::run(Function &F, +                                         FunctionAnalysisManager &AM) { +  F.viewCFGOnly(); +  return PreservedAnalyses::all(); +} + +static void writeCFGToDotFile(Function &F, bool CFGOnly = false) { +  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) +     return; +  std::string Filename = +      (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str(); +  errs() << "Writing '" << Filename << "'..."; + +  std::error_code EC; +  raw_fd_ostream File(Filename, EC, sys::fs::OF_Text); + +  if (!EC) +    WriteGraph(File, (const Function*)&F, CFGOnly); +  else +    errs() << "  error opening file for writing!"; +  errs() << "\n"; +} + +namespace { +  struct CFGPrinterLegacyPass : public FunctionPass { +    static char ID; // Pass identification, replacement for typeid +    CFGPrinterLegacyPass() : FunctionPass(ID) { +      initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); +    } + +    bool runOnFunction(Function &F) override { +      writeCFGToDotFile(F); +      return false; +    } + +    void print(raw_ostream &OS, const Module* = nullptr) const override {} + +    void getAnalysisUsage(AnalysisUsage &AU) const override { +      AU.setPreservesAll(); +    } +  }; +} + +char CFGPrinterLegacyPass::ID = 0; +INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file", +                false, true) + +PreservedAnalyses CFGPrinterPass::run(Function &F, +                                      FunctionAnalysisManager &AM) { +  writeCFGToDotFile(F); +  return PreservedAnalyses::all(); +} + +namespace { +  struct CFGOnlyPrinterLegacyPass : public FunctionPass { +    static char ID; // Pass identification, replacement for typeid +    CFGOnlyPrinterLegacyPass() : FunctionPass(ID) { +      initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); +    } + +    bool runOnFunction(Function &F) override { +      writeCFGToDotFile(F, /*CFGOnly=*/true); +      return false; +    } +    void print(raw_ostream &OS, const Module* = nullptr) const override {} + +    void getAnalysisUsage(AnalysisUsage &AU) const override { +      AU.setPreservesAll(); +    } +  }; +} + +char CFGOnlyPrinterLegacyPass::ID = 0; +INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", +   "Print CFG of function to 'dot' file (with no function bodies)", +   false, true) + +PreservedAnalyses CFGOnlyPrinterPass::run(Function &F, +                                          FunctionAnalysisManager &AM) { +  writeCFGToDotFile(F, /*CFGOnly=*/true); +  return PreservedAnalyses::all(); +} + +/// 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 +/// being a 'dot' and 'gv' program in your path. +/// +void Function::viewCFG() const { +  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) +     return; +  ViewGraph(this, "cfg" + getName()); +} + +/// 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 +/// this can make the graph smaller. +/// +void Function::viewCFGOnly() const { +  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) +     return; +  ViewGraph(this, "cfg" + getName(), true); +} + +FunctionPass *llvm::createCFGPrinterLegacyPassPass () { +  return new CFGPrinterLegacyPass(); +} + +FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () { +  return new CFGOnlyPrinterLegacyPass(); +} +  | 
