[llvm] 8b67853 - [CFGPrinter] Adding heat coloring to CFGPrinter

Kirill Naumov via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 8 13:00:18 PDT 2020


Author: Kirill Naumov
Date: 2020-04-08T19:59:51Z
New Revision: 8b67853a83c16f1e97a7bda02e3cceb37b1cd7db

URL: https://github.com/llvm/llvm-project/commit/8b67853a83c16f1e97a7bda02e3cceb37b1cd7db
DIFF: https://github.com/llvm/llvm-project/commit/8b67853a83c16f1e97a7bda02e3cceb37b1cd7db.diff

LOG: [CFGPrinter] Adding heat coloring to CFGPrinter

This patch introduces the heat coloring of the Control Flow Graph which is based
on the relative "hotness" of each BB. The patch is a part of sequence of three
patches, related to graphs Heat Coloring.

Reviewers: rcorcs, apilipenko, davidxl, sfertile, fedor.sergeev, eraman, bollu

Differential Revision: https://reviews.llvm.org/D77161

Added: 
    llvm/include/llvm/Analysis/HeatUtils.h
    llvm/lib/Analysis/HeatUtils.cpp
    llvm/test/Other/cfg-printer-branch-weights-percent.ll
    llvm/test/Other/heat-colors-graphs.ll

Modified: 
    llvm/include/llvm/Analysis/CFGPrinter.h
    llvm/lib/Analysis/CFGPrinter.cpp
    llvm/lib/Analysis/CMakeLists.txt
    llvm/test/Other/2007-06-05-PassID.ll
    llvm/test/Other/cfg-printer-branch-weights.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/CFGPrinter.h b/llvm/include/llvm/Analysis/CFGPrinter.h
index 80a26cd733fd..9f2195369a7c 100644
--- a/llvm/include/llvm/Analysis/CFGPrinter.h
+++ b/llvm/include/llvm/Analysis/CFGPrinter.h
@@ -20,6 +20,7 @@
 
 #include "llvm/Analysis/BlockFrequencyInfo.h"
 #include "llvm/Analysis/BranchProbabilityInfo.h"
+#include "llvm/Analysis/HeatUtils.h"
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
@@ -29,26 +30,22 @@
 #include "llvm/Support/GraphWriter.h"
 
 namespace llvm {
-class CFGViewerPass
-    : public PassInfoMixin<CFGViewerPass> {
+class CFGViewerPass : public PassInfoMixin<CFGViewerPass> {
 public:
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
-class CFGOnlyViewerPass
-    : public PassInfoMixin<CFGOnlyViewerPass> {
+class CFGOnlyViewerPass : public PassInfoMixin<CFGOnlyViewerPass> {
 public:
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
-class CFGPrinterPass
-    : public PassInfoMixin<CFGPrinterPass> {
+class CFGPrinterPass : public PassInfoMixin<CFGPrinterPass> {
 public:
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
 
-class CFGOnlyPrinterPass
-    : public PassInfoMixin<CFGOnlyPrinterPass> {
+class CFGOnlyPrinterPass : public PassInfoMixin<CFGOnlyPrinterPass> {
 public:
   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 };
@@ -58,13 +55,20 @@ class DOTFuncInfo {
   const Function *F;
   const BlockFrequencyInfo *BFI;
   const BranchProbabilityInfo *BPI;
+  uint64_t MaxFreq;
+  bool ShowHeat;
+  bool EdgeWeights;
+  bool RawWeights;
 
 public:
-  DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr) {}
+  DOTFuncInfo(const Function *F) : DOTFuncInfo(F, nullptr, nullptr, 0) {}
 
   DOTFuncInfo(const Function *F, const BlockFrequencyInfo *BFI,
-             BranchProbabilityInfo *BPI)
-      : F(F), BFI(BFI), BPI(BPI) {
+              BranchProbabilityInfo *BPI, uint64_t MaxFreq)
+      : F(F), BFI(BFI), BPI(BPI), MaxFreq(MaxFreq) {
+    ShowHeat = false;
+    EdgeWeights = true;
+    RawWeights = true;
   }
 
   const BlockFrequencyInfo *getBFI() { return BFI; }
@@ -72,6 +76,24 @@ class DOTFuncInfo {
   const BranchProbabilityInfo *getBPI() { return BPI; }
 
   const Function *getFunction() { return this->F; }
+
+  uint64_t getMaxFreq() { return MaxFreq; }
+
+  uint64_t getFreq(const BasicBlock *BB) {
+    return BFI->getBlockFreq(BB).getFrequency();
+  }
+
+  void setHeatColors(bool ShowHeat) { this->ShowHeat = ShowHeat; }
+
+  bool showHeatColors() { return ShowHeat; }
+
+  void setRawEdgeWeights(bool RawWeights) { this->RawWeights = RawWeights; }
+
+  bool useRawEdgeWeights() { return RawWeights; }
+
+  void setEdgeWeights(bool EdgeWeights) { this->EdgeWeights = EdgeWeights; }
+
+  bool showEdgeWeights() { return EdgeWeights; }
 };
 
 template <>
@@ -96,12 +118,13 @@ struct GraphTraits<DOTFuncInfo *> : public GraphTraits<const BasicBlock *> {
   }
 };
 
-template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
+template <>
+struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits {
 
   // Cache for is hidden property
-  llvm::DenseMap <const BasicBlock *, bool> isHiddenBasicBlock;
+  llvm::DenseMap<const BasicBlock *, bool> isHiddenBasicBlock;
 
-  DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+  DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
 
   static std::string getGraphName(DOTFuncInfo *CFGInfo) {
     return "CFG for '" + CFGInfo->getFunction()->getName().str() + "' function";
@@ -131,22 +154,23 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
 
     OS << *Node;
     std::string OutStr = OS.str();
-    if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
+    if (OutStr[0] == '\n')
+      OutStr.erase(OutStr.begin());
 
     // Process string output to make it nicer...
     unsigned ColNum = 0;
     unsigned LastSpace = 0;
     for (unsigned i = 0; i != OutStr.length(); ++i) {
-      if (OutStr[i] == '\n') {                            // Left justify
+      if (OutStr[i] == '\n') { // Left justify
         OutStr[i] = '\\';
-        OutStr.insert(OutStr.begin()+i+1, 'l');
+        OutStr.insert(OutStr.begin() + i + 1, 'l');
         ColNum = 0;
         LastSpace = 0;
-      } 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);
+      } 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;
-      } else if (ColNum == MaxColumns) {                  // Wrap lines.
+      } else if (ColNum == MaxColumns) { // Wrap lines.
         // Wrap very long names even though we can't find a space.
         if (!LastSpace)
           LastSpace = i;
@@ -154,8 +178,7 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
         ColNum = i - LastSpace;
         LastSpace = 0;
         i += 3; // The loop will advance 'i' again.
-      }
-      else
+      } else
         ++ColNum;
       if (OutStr[i] == ' ')
         LastSpace = i;
@@ -163,8 +186,7 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
     return OutStr;
   }
 
-  std::string getNodeLabel(const BasicBlock *Node,
-                           DOTFuncInfo *CFGInfo) {
+  std::string getNodeLabel(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
 
     if (isSimple())
       return getSimpleNodeLabel(Node, CFGInfo);
@@ -183,7 +205,8 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
     if (const SwitchInst *SI = dyn_cast<SwitchInst>(Node->getTerminator())) {
       unsigned SuccNo = I.getSuccessorIndex();
 
-      if (SuccNo == 0) return "def";
+      if (SuccNo == 0)
+        return "def";
 
       std::string Str;
       raw_string_ostream OS(Str);
@@ -197,9 +220,37 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
   /// Display the raw branch weights from PGO.
   std::string getEdgeAttributes(const BasicBlock *Node, const_succ_iterator I,
                                 DOTFuncInfo *CFGInfo) {
+    if (!CFGInfo->showEdgeWeights())
+      return "";
+
     const Instruction *TI = Node->getTerminator();
     if (TI->getNumSuccessors() == 1)
+      return "penwidth=2";
+
+    unsigned OpNo = I.getSuccessorIndex();
+
+    if (OpNo >= TI->getNumSuccessors())
       return "";
+
+    BasicBlock *SuccBB = TI->getSuccessor(OpNo);
+    auto BranchProb = CFGInfo->getBPI()->getEdgeProbability(Node, SuccBB);
+    double WeightPercent = ((double)BranchProb.getNumerator()) /
+                           ((double)BranchProb.getDenominator());
+    double Width = 1 + WeightPercent;
+
+    if (!CFGInfo->useRawEdgeWeights())
+      return formatv("label=\"{0:P}\" penwidth={1}", WeightPercent, Width)
+          .str();
+
+    // Prepend a 'W' to indicate that this is a weight rather than the actual
+    // profile count (due to scaling).
+
+    uint64_t Freq = CFGInfo->getFreq(Node);
+    std::string Attrs = formatv("label=\"W:{0}\" penwidth={1}",
+                                (uint64_t)(Freq * WeightPercent), Width);
+    if (Attrs.size())
+      return Attrs;
+
     MDNode *WeightsNode = TI->getMetadata(LLVMContext::MD_prof);
     if (!WeightsNode)
       return "";
@@ -207,17 +258,32 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
     MDString *MDName = cast<MDString>(WeightsNode->getOperand(0));
     if (MDName->getString() != "branch_weights")
       return "";
-    unsigned OpNo = I.getSuccessorIndex() + 1;
+
+    OpNo = I.getSuccessorIndex() + 1;
     if (OpNo >= WeightsNode->getNumOperands())
       return "";
     ConstantInt *Weight =
         mdconst::dyn_extract<ConstantInt>(WeightsNode->getOperand(OpNo));
     if (!Weight)
       return "";
+    return ("label=\"W:" + std::to_string(Weight->getZExtValue()) +
+            "\" penwidth=" + std::to_string(Width));
+  }
 
-    // Prepend a 'W' to indicate that this is a weight rather than the actual
-    // profile count (due to scaling).
-    return ("label=\"W:" + Twine(Weight->getZExtValue()) + "\"").str();
+  std::string getNodeAttributes(const BasicBlock *Node, DOTFuncInfo *CFGInfo) {
+
+    if (!CFGInfo->showHeatColors())
+      return "";
+
+    uint64_t Freq = CFGInfo->getFreq(Node);
+    std::string Color = getHeatColor(Freq, CFGInfo->getMaxFreq());
+    std::string EdgeColor = (Freq <= (CFGInfo->getMaxFreq() / 2))
+                                ? (getHeatColor(0))
+                                : (getHeatColor(1));
+
+    std::string Attrs = "color=\"" + EdgeColor + "ff\", style=filled," +
+                        " fillcolor=\"" + Color + "70\"";
+    return Attrs;
   }
   bool isNodeHidden(const BasicBlock *Node);
   void computeHiddenNodes(const Function *F);
@@ -225,9 +291,9 @@ template <> struct DOTGraphTraits<DOTFuncInfo *> : public DefaultDOTGraphTraits
 } // End llvm namespace
 
 namespace llvm {
-  class FunctionPass;
-  FunctionPass *createCFGPrinterLegacyPassPass ();
-  FunctionPass *createCFGOnlyPrinterLegacyPassPass ();
+class FunctionPass;
+FunctionPass *createCFGPrinterLegacyPassPass();
+FunctionPass *createCFGOnlyPrinterLegacyPassPass();
 } // End llvm namespace
 
 #endif

diff  --git a/llvm/include/llvm/Analysis/HeatUtils.h b/llvm/include/llvm/Analysis/HeatUtils.h
new file mode 100644
index 000000000000..ed6044c422a2
--- /dev/null
+++ b/llvm/include/llvm/Analysis/HeatUtils.h
@@ -0,0 +1,38 @@
+//===-- HeatUtils.h - Utility for printing heat colors ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for printing heat colors based on profiling information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_HEATUTILS_H
+#define LLVM_ANALYSIS_HEATUTILS_H
+
+#include "llvm/Analysis/BlockFrequencyInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+
+#include <string>
+
+namespace llvm {
+
+// Returns the maximum frequency of a BB in a function.
+uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI);
+
+// Calculates heat color based on current and maximum frequencies.
+std::string getHeatColor(uint64_t freq, uint64_t maxFreq);
+
+// Calculates heat color based on percent of "hotness".
+std::string getHeatColor(double percent);
+
+} // namespace llvm
+
+#endif

diff  --git a/llvm/lib/Analysis/CFGPrinter.cpp b/llvm/lib/Analysis/CFGPrinter.cpp
index 295d936c026e..7856b9731753 100644
--- a/llvm/lib/Analysis/CFGPrinter.cpp
+++ b/llvm/lib/Analysis/CFGPrinter.cpp
@@ -17,8 +17,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/Analysis/CFGPrinter.h"
+#include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/CommandLine.h"
@@ -27,24 +27,37 @@
 
 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>
+    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."));
 
 static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",
-            cl::init(false));
+                                          cl::init(false));
 
 static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",
-            cl::init(false));
+                                         cl::init(false));
+
+static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(false),
+                                    cl::Hidden,
+                                    cl::desc("Show heat colors in CFG"));
+
+static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),
+                                      cl::Hidden,
+                                      cl::desc("Use raw weights for labels. "
+                                               "Use percentages as default."));
+
+static cl::opt<bool>
+    ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,
+                   cl::desc("Show edges labeled with weights"));
 
 static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
-                                 BranchProbabilityInfo *BPI,
-                                 bool isSimple) {
+                              BranchProbabilityInfo *BPI, uint64_t MaxFreq,
+                              bool CFGOnly = false) {
   std::string Filename =
       (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
   errs() << "Writing '" << Filename << "'...";
@@ -52,81 +65,88 @@ static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
   std::error_code EC;
   raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
 
-  DOTFuncInfo CFGInfo(&F, BFI, BPI);
+  DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
+  CFGInfo.setHeatColors(ShowHeatColors);
+  CFGInfo.setEdgeWeights(ShowEdgeWeight);
+  CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
+
   if (!EC)
-    WriteGraph(File, &CFGInfo, isSimple);
+    WriteGraph(File, &CFGInfo, CFGOnly);
   else
     errs() << "  error opening file for writing!";
   errs() << "\n";
 }
 
 static void viewCFG(Function &F, BlockFrequencyInfo *BFI,
-                                 BranchProbabilityInfo *BPI,
-                                 bool isSimple) {
-  DOTFuncInfo CFGInfo(&F, BFI, BPI);
-  ViewGraph(&CFGInfo, "cfg." + F.getName(), isSimple);
+                    BranchProbabilityInfo *BPI, uint64_t MaxFreq,
+                    bool CFGOnly = false) {
+  DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
+  CFGInfo.setHeatColors(ShowHeatColors);
+  CFGInfo.setEdgeWeights(ShowEdgeWeight);
+  CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
+
+  ViewGraph(&CFGInfo, "cfg." + F.getName(), CFGOnly);
 }
 
 namespace {
-  struct CFGViewerLegacyPass : public FunctionPass {
-    static char ID; // Pass identifcation, replacement for typeid
-    CFGViewerLegacyPass() : FunctionPass(ID) {
-      initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
-    }
-
-    bool runOnFunction(Function &F) override {
-      auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
-      auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
-      viewCFG(F, BFI, BPI, /*isSimple=*/false);
-      return false;
-    }
+struct CFGViewerLegacyPass : public FunctionPass {
+  static char ID; // Pass identifcation, replacement for typeid
+  CFGViewerLegacyPass() : FunctionPass(ID) {
+    initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override {
+    auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+    auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+    viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
+    return false;
+  }
 
-    void print(raw_ostream &OS, const Module* = nullptr) const override {}
+  void print(raw_ostream &OS, const Module * = nullptr) const override {}
 
-    void getAnalysisUsage(AnalysisUsage &AU) const override {
-      FunctionPass::getAnalysisUsage(AU); // Maybe Change to FunctionPass::...
-      AU.addRequired<BlockFrequencyInfoWrapperPass>();
-      AU.addRequired<BranchProbabilityInfoWrapperPass>();
-      AU.setPreservesAll();
-    }
-  };
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    FunctionPass::getAnalysisUsage(AU);
+    AU.addRequired<BlockFrequencyInfoWrapperPass>();
+    AU.addRequired<BranchProbabilityInfoWrapperPass>();
+    AU.setPreservesAll();
+  }
+};
 }
 
 char CFGViewerLegacyPass::ID = 0;
-INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
+INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false,
+                true)
 
-PreservedAnalyses CFGViewerPass::run(Function &F,
-                                     FunctionAnalysisManager &AM) {
+PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) {
   auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
   auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
-  viewCFG(F, BFI, BPI, /*isSimple=*/false);
+  viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
   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 {
-      auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
-      auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
-      viewCFG(F, BFI, BPI, /*isSimple=*/false);
-      return false;
-    }
+struct CFGOnlyViewerLegacyPass : public FunctionPass {
+  static char ID; // Pass identifcation, replacement for typeid
+  CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
+    initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override {
+    auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+    auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+    viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
+    return false;
+  }
 
-    void print(raw_ostream &OS, const Module* = nullptr) const override {}
+  void print(raw_ostream &OS, const Module * = nullptr) const override {}
 
-    void getAnalysisUsage(AnalysisUsage &AU) const override {
-      FunctionPass::getAnalysisUsage(AU);
-      AU.addRequired<BlockFrequencyInfoWrapperPass>();
-      AU.addRequired<BranchProbabilityInfoWrapperPass>();
-      AU.setPreservesAll();
-    }
-  };
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    FunctionPass::getAnalysisUsage(AU);
+    AU.addRequired<BlockFrequencyInfoWrapperPass>();
+    AU.addRequired<BranchProbabilityInfoWrapperPass>();
+    AU.setPreservesAll();
+  }
+};
 }
 
 char CFGOnlyViewerLegacyPass::ID = 0;
@@ -137,81 +157,81 @@ PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
                                          FunctionAnalysisManager &AM) {
   auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
   auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
-  viewCFG(F, BFI, BPI, /*isSimple=*/false);
+  viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
   return PreservedAnalyses::all();
 }
 
 namespace {
-  struct CFGPrinterLegacyPass : public FunctionPass {
-    static char ID; // Pass identification, replacement for typeid
-    CFGPrinterLegacyPass() : FunctionPass(ID) {
-      initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
-    }
-
-    bool runOnFunction(Function &F) override {
-      auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
-      auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
-      writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
-      return false;
-    }
+struct CFGPrinterLegacyPass : public FunctionPass {
+  static char ID; // Pass identification, replacement for typeid
+  CFGPrinterLegacyPass() : FunctionPass(ID) {
+    initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override {
+    auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+    auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+    writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
+    return false;
+  }
 
-    void print(raw_ostream &OS, const Module* = nullptr) const override {}
+  void print(raw_ostream &OS, const Module * = nullptr) const override {}
 
-    void getAnalysisUsage(AnalysisUsage &AU) const override {
-      FunctionPass::getAnalysisUsage(AU);
-      AU.addRequired<BlockFrequencyInfoWrapperPass>();
-      AU.addRequired<BranchProbabilityInfoWrapperPass>();
-      AU.setPreservesAll();
-    }
-  };
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    FunctionPass::getAnalysisUsage(AU);
+    AU.addRequired<BlockFrequencyInfoWrapperPass>();
+    AU.addRequired<BranchProbabilityInfoWrapperPass>();
+    AU.setPreservesAll();
+  }
+};
 }
 
 char CFGPrinterLegacyPass::ID = 0;
-INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file",
-                false, true)
+INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg",
+                "Print CFG of function to 'dot' file", false, true)
 
 PreservedAnalyses CFGPrinterPass::run(Function &F,
                                       FunctionAnalysisManager &AM) {
   auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
   auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
-  writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
+  writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI));
   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 {
-      auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
-      auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
-      writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
-      return false;
-    }
-    void print(raw_ostream &OS, const Module* = nullptr) const override {}
-
-    void getAnalysisUsage(AnalysisUsage &AU) const override {
-      FunctionPass::getAnalysisUsage(AU);
-      AU.addRequired<BlockFrequencyInfoWrapperPass>();
-      AU.addRequired<BranchProbabilityInfoWrapperPass>();
-      AU.setPreservesAll();
-    }
-  };
+struct CFGOnlyPrinterLegacyPass : public FunctionPass {
+  static char ID; // Pass identification, replacement for typeid
+  CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
+    initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
+  }
+
+  bool runOnFunction(Function &F) override {
+    auto *BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+    auto *BFI = &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
+    writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
+    return false;
+  }
+  void print(raw_ostream &OS, const Module * = nullptr) const override {}
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    FunctionPass::getAnalysisUsage(AU);
+    AU.addRequired<BlockFrequencyInfoWrapperPass>();
+    AU.addRequired<BranchProbabilityInfoWrapperPass>();
+    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)
+                "Print CFG of function to 'dot' file (with no function bodies)",
+                false, true)
 
 PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
                                           FunctionAnalysisManager &AM) {
   auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
   auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
-  writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false);
+  writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
   return PreservedAnalyses::all();
 }
 
@@ -222,7 +242,7 @@ PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
 ///
 void Function::viewCFG() const {
   if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
-     return;
+    return;
   DOTFuncInfo CFGInfo(this);
   ViewGraph(&CFGInfo, "cfg" + getName());
 }
@@ -234,16 +254,16 @@ void Function::viewCFG() const {
 ///
 void Function::viewCFGOnly() const {
   if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
-     return;
+    return;
   DOTFuncInfo CFGInfo(this);
   ViewGraph(&CFGInfo, "cfg" + getName(), true);
 }
 
-FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
+FunctionPass *llvm::createCFGPrinterLegacyPassPass() {
   return new CFGPrinterLegacyPass();
 }
 
-FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
+FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass() {
   return new CFGOnlyPrinterLegacyPass();
 }
 
@@ -252,8 +272,8 @@ void DOTGraphTraits<DOTFuncInfo *>::computeHiddenNodes(const Function *F) {
     if (succ_begin(Node) == succ_end(Node)) {
       const Instruction *TI = Node->getTerminator();
       isHiddenBasicBlock[Node] =
-        (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
-        (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
+          (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
+          (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
       return;
     }
     isHiddenBasicBlock[Node] = std::all_of(

diff  --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index 8a658aa6adf7..dccd3d7f3f96 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -35,6 +35,7 @@ add_llvm_component_library(LLVMAnalysis
   EHPersonalities.cpp
   GlobalsModRef.cpp
   GuardUtils.cpp
+  HeatUtils.cpp
   IVDescriptors.cpp
   IVUsers.cpp
   IndirectCallPromotionAnalysis.cpp

diff  --git a/llvm/lib/Analysis/HeatUtils.cpp b/llvm/lib/Analysis/HeatUtils.cpp
new file mode 100644
index 000000000000..aac4fe15068d
--- /dev/null
+++ b/llvm/lib/Analysis/HeatUtils.cpp
@@ -0,0 +1,64 @@
+//===-- HeatUtils.cpp - Utility for printing heat colors --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for printing heat colors based on heuristics or profiling
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/HeatUtils.h"
+#include "llvm/IR/Instructions.h"
+
+namespace llvm {
+
+static const unsigned heatSize = 100;
+static const std::string heatPalette[heatSize] = {
+    "#3d50c3", "#4055c8", "#4358cb", "#465ecf", "#4961d2", "#4c66d6", "#4f69d9",
+    "#536edd", "#5572df", "#5977e3", "#5b7ae5", "#5f7fe8", "#6282ea", "#6687ed",
+    "#6a8bef", "#6c8ff1", "#7093f3", "#7396f5", "#779af7", "#7a9df8", "#7ea1fa",
+    "#81a4fb", "#85a8fc", "#88abfd", "#8caffe", "#8fb1fe", "#93b5fe", "#96b7ff",
+    "#9abbff", "#9ebeff", "#a1c0ff", "#a5c3fe", "#a7c5fe", "#abc8fd", "#aec9fc",
+    "#b2ccfb", "#b5cdfa", "#b9d0f9", "#bbd1f8", "#bfd3f6", "#c1d4f4", "#c5d6f2",
+    "#c7d7f0", "#cbd8ee", "#cedaeb", "#d1dae9", "#d4dbe6", "#d6dce4", "#d9dce1",
+    "#dbdcde", "#dedcdb", "#e0dbd8", "#e3d9d3", "#e5d8d1", "#e8d6cc", "#ead5c9",
+    "#ecd3c5", "#eed0c0", "#efcebd", "#f1ccb8", "#f2cab5", "#f3c7b1", "#f4c5ad",
+    "#f5c1a9", "#f6bfa6", "#f7bca1", "#f7b99e", "#f7b599", "#f7b396", "#f7af91",
+    "#f7ac8e", "#f7a889", "#f6a385", "#f5a081", "#f59c7d", "#f4987a", "#f39475",
+    "#f29072", "#f08b6e", "#ef886b", "#ed8366", "#ec7f63", "#e97a5f", "#e8765c",
+    "#e57058", "#e36c55", "#e16751", "#de614d", "#dc5d4a", "#d85646", "#d65244",
+    "#d24b40", "#d0473d", "#cc403a", "#ca3b37", "#c53334", "#c32e31", "#be242e",
+    "#bb1b2c", "#b70d28"};
+
+uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI) {
+  uint64_t maxFreq = 0;
+  for (const BasicBlock &BB : F) {
+    uint64_t freqVal = BFI->getBlockFreq(&BB).getFrequency();
+    if (freqVal >= maxFreq)
+      maxFreq = freqVal;
+  }
+  return maxFreq;
+}
+
+std::string getHeatColor(uint64_t freq, uint64_t maxFreq) {
+  if (freq > maxFreq)
+    freq = maxFreq;
+  double percent = log2(double(freq)) / log2(maxFreq);
+  return getHeatColor(percent);
+}
+
+std::string getHeatColor(double percent) {
+  if (percent > 1.0)
+    percent = 1.0;
+  if (percent < 0.0)
+    percent = 0.0;
+  unsigned colorId = unsigned(round(percent * (heatSize - 1.0)));
+  return heatPalette[colorId];
+}
+
+} // namespace llvm
\ No newline at end of file

diff  --git a/llvm/test/Other/2007-06-05-PassID.ll b/llvm/test/Other/2007-06-05-PassID.ll
index 386e444caae1..6964f2824d68 100644
--- a/llvm/test/Other/2007-06-05-PassID.ll
+++ b/llvm/test/Other/2007-06-05-PassID.ll
@@ -1,5 +1,13 @@
 ;RUN: opt < %s -analyze -dot-cfg-only 2>/dev/null
 ;RUN: opt < %s -analyze -passes=dot-cfg-only 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg-only \
+;RUN:          -cfg-heat-colors=true -cfg-weights=true 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg-only \
+;RUN:          -cfg-heat-colors=false -cfg-weights=false 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg \
+;RUN:          -cfg-heat-colors=true -cfg-weights=true 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg \
+;RUN:          -cfg-heat-colors=false -cfg-weights=false 2>/dev/null
 ;PR 1497
 
 define void @foo() {

diff  --git a/llvm/test/Other/cfg-printer-branch-weights-percent.ll b/llvm/test/Other/cfg-printer-branch-weights-percent.ll
new file mode 100644
index 000000000000..bfbb73160444
--- /dev/null
+++ b/llvm/test/Other/cfg-printer-branch-weights-percent.ll
@@ -0,0 +1,19 @@
+;RUN: opt < %s -analyze -dot-cfg -cfg-weights -cfg-dot-filename-prefix=%t 2>/dev/null
+;RUN: FileCheck %s -input-file=%t.f.dot
+
+define void @f(i32) {
+entry:
+  %check = icmp sgt i32 %0, 0
+  br i1 %check, label %if, label %exit, !prof !0
+
+; CHECK: label="0.50%"
+; CHECK-NOT: ["];
+if:                     ; preds = %entry
+  br label %exit
+; CHECK: label="99.50%"
+; CHECK-NOT: ["];
+exit:                   ; preds = %entry, %if
+  ret void
+}
+
+!0 = !{!"branch_weights", i32 1, i32 200}

diff  --git a/llvm/test/Other/cfg-printer-branch-weights.ll b/llvm/test/Other/cfg-printer-branch-weights.ll
index 200bc7d1fdde..a7a53c38653c 100644
--- a/llvm/test/Other/cfg-printer-branch-weights.ll
+++ b/llvm/test/Other/cfg-printer-branch-weights.ll
@@ -1,4 +1,4 @@
-;RUN: opt < %s -analyze -dot-cfg -cfg-dot-filename-prefix=%t 2>/dev/null
+;RUN: opt < %s -analyze -dot-cfg -cfg-weights -cfg-raw-weights -cfg-dot-filename-prefix=%t 2>/dev/null
 ;RUN: FileCheck %s -input-file=%t.f.dot
 
 define void @f(i32) {
@@ -6,11 +6,11 @@ entry:
   %check = icmp sgt i32 %0, 0
   br i1 %check, label %if, label %exit, !prof !0
 
-; CHECK: label="W:1"
+; CHECK: label="W:7"
 ; CHECK-NOT: ["];
 if:                     ; preds = %entry
   br label %exit
-; CHECK: label="W:200"
+; CHECK: label="W:1600"
 ; CHECK-NOT: ["];
 exit:                   ; preds = %entry, %if
   ret void

diff  --git a/llvm/test/Other/heat-colors-graphs.ll b/llvm/test/Other/heat-colors-graphs.ll
new file mode 100644
index 000000000000..1ec3601c7ff4
--- /dev/null
+++ b/llvm/test/Other/heat-colors-graphs.ll
@@ -0,0 +1,19 @@
+; RUN: opt < %s -analyze -dot-cfg -cfg-heat-colors -cfg-dot-filename-prefix=%t 2>/dev/null
+; RUN: FileCheck %s -input-file=%t.f.dot
+
+; CHECK: color="#{{[(a-z)(0-9)]+}}", style={{[a-z]+}}, fillcolor="#{{[(a-z)(0-9)]+}}"
+; CHECK: color="#{{[(a-z)(0-9)]+}}", style={{[a-z]+}}, fillcolor="#{{[(a-z)(0-9)]+}}"
+; CHECK: color="#{{[(a-z)(0-9)]+}}", style={{[a-z]+}}, fillcolor="#{{[(a-z)(0-9)]+}}"
+
+define void @f(i32) {
+entry:
+  %check = icmp sgt i32 %0, 0
+  br i1 %check, label %if, label %exit, !prof !0
+
+if:                     ; preds = %entry
+  br label %exit
+exit:                   ; preds = %entry, %if
+  ret void
+}
+
+!0 = !{!"branch_weights", i32 1, i32 200}


        


More information about the llvm-commits mailing list