brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 38aad84 Raw
263 lines · cpp
1//===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines a `-dot-cfg` analysis pass, which emits the10// `<prefix>.<fnname>.dot` file for each function in the program, with a graph11// of the CFG for that function. The default value for `<prefix>` is `cfg` but12// can be customized as needed.13//14// The other main feature of this file is that it implements the15// Function::viewCFG method, which is useful for debugging passes which operate16// on the CFG.17//18//===----------------------------------------------------------------------===//19 20#include "llvm/Analysis/CFGPrinter.h"21#include "llvm/ADT/PostOrderIterator.h"22#include "llvm/IR/ModuleSlotTracker.h"23#include "llvm/Support/CommandLine.h"24#include "llvm/Support/FileSystem.h"25#include "llvm/Support/GraphWriter.h"26 27using namespace llvm;28 29static cl::opt<std::string>30    CFGFuncName("cfg-func-name", cl::Hidden,31                cl::desc("The name of a function (or its substring)"32                         " whose CFG is viewed/printed."));33 34static cl::opt<std::string> CFGDotFilenamePrefix(35    "cfg-dot-filename-prefix", cl::Hidden,36    cl::desc("The prefix used for the CFG dot file names."));37 38static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",39                                          cl::init(false));40 41static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",42                                         cl::init(false));43 44static cl::opt<double> HideColdPaths(45    "cfg-hide-cold-paths", cl::init(0.0),46    cl::desc("Hide blocks with relative frequency below the given value"));47 48static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(true),49                                    cl::Hidden,50                                    cl::desc("Show heat colors in CFG"));51 52static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),53                                      cl::Hidden,54                                      cl::desc("Use raw weights for labels. "55                                               "Use percentages as default."));56 57static cl::opt<bool>58    ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,59                   cl::desc("Show edges labeled with weights"));60 61static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,62                              BranchProbabilityInfo *BPI, uint64_t MaxFreq,63                              bool CFGOnly = false) {64  std::string Filename =65      (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();66  errs() << "Writing '" << Filename << "'...";67 68  std::error_code EC;69  raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);70 71  DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);72  CFGInfo.setHeatColors(ShowHeatColors);73  CFGInfo.setEdgeWeights(ShowEdgeWeight);74  CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);75 76  if (!EC)77    WriteGraph(File, &CFGInfo, CFGOnly);78  else79    errs() << "  error opening file for writing!";80  errs() << "\n";81}82 83static void viewCFG(Function &F, const BlockFrequencyInfo *BFI,84                    const BranchProbabilityInfo *BPI, uint64_t MaxFreq,85                    bool CFGOnly = false) {86  DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);87  CFGInfo.setHeatColors(ShowHeatColors);88  CFGInfo.setEdgeWeights(ShowEdgeWeight);89  CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);90 91  ViewGraph(&CFGInfo, "cfg." + F.getName(), CFGOnly);92}93 94DOTFuncInfo::DOTFuncInfo(const Function *F, const BlockFrequencyInfo *BFI,95                         const BranchProbabilityInfo *BPI, uint64_t MaxFreq)96    : F(F), BFI(BFI), BPI(BPI), MaxFreq(MaxFreq) {97  ShowHeat = false;98  EdgeWeights = !!BPI; // Print EdgeWeights when BPI is available.99  RawWeights = !!BFI;  // Print RawWeights when BFI is available.100}101 102DOTFuncInfo::~DOTFuncInfo() = default;103 104ModuleSlotTracker *DOTFuncInfo::getModuleSlotTracker() {105  if (!MSTStorage)106    MSTStorage = std::make_unique<ModuleSlotTracker>(F->getParent());107  return &*MSTStorage;108}109 110PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) {111  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))112    return PreservedAnalyses::all();113  auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);114  auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);115  viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));116  return PreservedAnalyses::all();117}118 119PreservedAnalyses CFGOnlyViewerPass::run(Function &F,120                                         FunctionAnalysisManager &AM) {121  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))122    return PreservedAnalyses::all();123  auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);124  auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);125  viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);126  return PreservedAnalyses::all();127}128 129PreservedAnalyses CFGPrinterPass::run(Function &F,130                                      FunctionAnalysisManager &AM) {131  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))132    return PreservedAnalyses::all();133  auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);134  auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);135  writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));136  return PreservedAnalyses::all();137}138 139PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,140                                          FunctionAnalysisManager &AM) {141  if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName))142    return PreservedAnalyses::all();143  auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);144  auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);145  writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);146  return PreservedAnalyses::all();147}148 149/// viewCFG - This function is meant for use from the debugger.  You can just150/// say 'call F->viewCFG()' and a ghostview window should pop up from the151/// program, displaying the CFG of the current function.  This depends on there152/// being a 'dot' and 'gv' program in your path.153///154void Function::viewCFG() const { viewCFG(false, nullptr, nullptr); }155 156void Function::viewCFG(const char *OutputFileName) const {157  viewCFG(false, nullptr, nullptr, OutputFileName);158}159 160void Function::viewCFG(bool ViewCFGOnly, const BlockFrequencyInfo *BFI,161                       const BranchProbabilityInfo *BPI,162                       const char *OutputFileName) const {163  if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))164    return;165  DOTFuncInfo CFGInfo(this, BFI, BPI, BFI ? getMaxFreq(*this, BFI) : 0);166  ViewGraph(&CFGInfo, OutputFileName ? OutputFileName : "cfg" + getName(),167            ViewCFGOnly);168}169 170/// viewCFGOnly - This function is meant for use from the debugger.  It works171/// just like viewCFG, but it does not include the contents of basic blocks172/// into the nodes, just the label.  If you are only interested in the CFG173/// this can make the graph smaller.174///175void Function::viewCFGOnly() const { viewCFGOnly(nullptr, nullptr); }176 177void Function::viewCFGOnly(const char *OutputFileName) const {178  viewCFG(true, nullptr, nullptr, OutputFileName);179}180 181void Function::viewCFGOnly(const BlockFrequencyInfo *BFI,182                           const BranchProbabilityInfo *BPI) const {183  viewCFG(true, BFI, BPI);184}185 186/// Find all blocks on the paths which terminate with a deoptimize or 187/// unreachable (i.e. all blocks which are post-dominated by a deoptimize 188/// or unreachable). These paths are hidden if the corresponding cl::opts189/// are enabled.190void DOTGraphTraits<DOTFuncInfo *>::computeDeoptOrUnreachablePaths(191    const Function *F) {192  auto evaluateBB = [&](const BasicBlock *Node) {193    if (succ_empty(Node)) {194      const Instruction *TI = Node->getTerminator();195      isOnDeoptOrUnreachablePath[Node] =196          (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||197          (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());198      return;199    }200    isOnDeoptOrUnreachablePath[Node] =201        llvm::all_of(successors(Node), [this](const BasicBlock *BB) {202          return isOnDeoptOrUnreachablePath[BB];203        });204  };205  /// The post order traversal iteration is done to know the status of206  /// isOnDeoptOrUnreachablePath for all the successors on the current BB.207  llvm::for_each(post_order(&F->getEntryBlock()), evaluateBB);208}209 210bool DOTGraphTraits<DOTFuncInfo *>::isNodeHidden(const BasicBlock *Node,211                                                 const DOTFuncInfo *CFGInfo) {212  if (HideColdPaths.getNumOccurrences() > 0)213    if (auto *BFI = CFGInfo->getBFI()) {214      BlockFrequency NodeFreq = BFI->getBlockFreq(Node);215      BlockFrequency EntryFreq = BFI->getEntryFreq();216      // Hide blocks with relative frequency below HideColdPaths threshold.217      if ((double)NodeFreq.getFrequency() / EntryFreq.getFrequency() <218          HideColdPaths)219        return true;220    }221  if (HideUnreachablePaths || HideDeoptimizePaths) {222    if (!isOnDeoptOrUnreachablePath.contains(Node))223      computeDeoptOrUnreachablePaths(Node->getParent());224    return isOnDeoptOrUnreachablePath[Node];225  }226  return false;227}228 229std::string DOTGraphTraits<DOTFuncInfo *>::getCompleteNodeLabel(230    const BasicBlock *Node, DOTFuncInfo *CFGInfo,231    function_ref<void(raw_string_ostream &, const BasicBlock &)>232        HandleBasicBlock,233    function_ref<void(std::string &, unsigned &, unsigned)> HandleComment) {234  if (HandleBasicBlock)235    return CompleteNodeLabelString(Node, HandleBasicBlock, HandleComment);236 237  // Default basic block printing238  std::optional<ModuleSlotTracker> MSTStorage;239  ModuleSlotTracker *MST = nullptr;240 241  if (CFGInfo) {242    MST = CFGInfo->getModuleSlotTracker();243  } else {244    MSTStorage.emplace(Node->getModule());245    MST = &*MSTStorage;246  }247 248  return CompleteNodeLabelString(249      Node,250      function_ref<void(raw_string_ostream &, const BasicBlock &)>(251          [MST](raw_string_ostream &OS, const BasicBlock &Node) -> void {252            // Prepend label name253            Node.printAsOperand(OS, false, *MST);254            OS << ":\n";255 256            for (const Instruction &Inst : Node) {257              Inst.print(OS, *MST, /* IsForDebug */ false);258              OS << '\n';259            }260          }),261      HandleComment);262}263