diff --git a/llvm/include/llvm/Analysis/CFGPrinter.h b/llvm/include/llvm/Analysis/CFGPrinter.h --- 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 { +class CFGViewerPass : public PassInfoMixin { public: PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; -class CFGOnlyViewerPass - : public PassInfoMixin { +class CFGOnlyViewerPass : public PassInfoMixin { public: PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; -class CFGPrinterPass - : public PassInfoMixin { +class CFGPrinterPass : public PassInfoMixin { public: PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; -class CFGOnlyPrinterPass - : public PassInfoMixin { +class CFGOnlyPrinterPass : public PassInfoMixin { public: PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; @@ -58,13 +55,20 @@ 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 @@ 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 @@ } }; -template <> struct DOTGraphTraits : public DefaultDOTGraphTraits { +template <> +struct DOTGraphTraits : public DefaultDOTGraphTraits { // Cache for is hidden property - llvm::DenseMap isHiddenBasicBlock; + llvm::DenseMap 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 @@ 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 @@ 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 @@ 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 @@ if (const SwitchInst *SI = dyn_cast(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 @@ /// 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 @@ MDString *MDName = cast(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(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 @@ } // 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 --- /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 + +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 --- 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 CFGFuncName( - "cfg-func-name", cl::Hidden, - cl::desc("The name of a function (or its substring)" - " whose CFG is viewed/printed.")); +static cl::opt + CFGFuncName("cfg-func-name", cl::Hidden, + cl::desc("The name of a function (or its substring)" + " whose CFG is viewed/printed.")); static cl::opt CFGDotFilenamePrefix( "cfg-dot-filename-prefix", cl::Hidden, cl::desc("The prefix used for the CFG dot file names.")); static cl::opt HideUnreachablePaths("cfg-hide-unreachable-paths", - cl::init(false)); + cl::init(false)); static cl::opt HideDeoptimizePaths("cfg-hide-deoptimize-paths", - cl::init(false)); + cl::init(false)); + +static cl::opt ShowHeatColors("cfg-heat-colors", cl::init(false), + cl::Hidden, + cl::desc("Show heat colors in CFG")); + +static cl::opt UseRawEdgeWeight("cfg-raw-weights", cl::init(false), + cl::Hidden, + cl::desc("Use raw weights for labels. " + "Use percentages as default.")); + +static cl::opt + 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 @@ 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().getBPI(); - auto *BFI = &getAnalysis().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().getBPI(); + auto *BFI = &getAnalysis().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(); - AU.addRequired(); - AU.setPreservesAll(); - } - }; + void getAnalysisUsage(AnalysisUsage &AU) const override { + FunctionPass::getAnalysisUsage(AU); + AU.addRequired(); + AU.addRequired(); + 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(F); auto *BPI = &AM.getResult(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().getBPI(); - auto *BFI = &getAnalysis().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().getBPI(); + auto *BFI = &getAnalysis().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(); - AU.addRequired(); - AU.setPreservesAll(); - } - }; + void getAnalysisUsage(AnalysisUsage &AU) const override { + FunctionPass::getAnalysisUsage(AU); + AU.addRequired(); + AU.addRequired(); + AU.setPreservesAll(); + } +}; } char CFGOnlyViewerLegacyPass::ID = 0; @@ -137,81 +157,81 @@ FunctionAnalysisManager &AM) { auto *BFI = &AM.getResult(F); auto *BPI = &AM.getResult(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().getBPI(); - auto *BFI = &getAnalysis().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().getBPI(); + auto *BFI = &getAnalysis().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(); - AU.addRequired(); - AU.setPreservesAll(); - } - }; + void getAnalysisUsage(AnalysisUsage &AU) const override { + FunctionPass::getAnalysisUsage(AU); + AU.addRequired(); + AU.addRequired(); + 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(F); auto *BPI = &AM.getResult(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().getBPI(); - auto *BFI = &getAnalysis().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(); - AU.addRequired(); - 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().getBPI(); + auto *BFI = &getAnalysis().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(); + AU.addRequired(); + 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(F); auto *BPI = &AM.getResult(F); - writeCFGToDotFile(F, BFI, BPI, /*isSimple=*/false); + writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true); return PreservedAnalyses::all(); } @@ -222,7 +242,7 @@ /// 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::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 @@ if (succ_begin(Node) == succ_end(Node)) { const Instruction *TI = Node->getTerminator(); isHiddenBasicBlock[Node] = - (HideUnreachablePaths && isa(TI)) || - (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall()); + (HideUnreachablePaths && isa(TI)) || + (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall()); return; } isHiddenBasicBlock[Node] = std::all_of( diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -35,6 +35,7 @@ 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 --- /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 --- 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.ll b/llvm/test/Other/cfg-printer-branch-weights-percent.ll copy from llvm/test/Other/cfg-printer-branch-weights.ll copy to llvm/test/Other/cfg-printer-branch-weights-percent.ll --- a/llvm/test/Other/cfg-printer-branch-weights.ll +++ b/llvm/test/Other/cfg-printer-branch-weights-percent.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-dot-filename-prefix=%t 2>/dev/null ;RUN: FileCheck %s -input-file=%t.f.dot define void @f(i32) { @@ -6,11 +6,11 @@ %check = icmp sgt i32 %0, 0 br i1 %check, label %if, label %exit, !prof !0 -; CHECK: label="W:1" +; CHECK: label="0.50%" ; CHECK-NOT: ["]; if: ; preds = %entry br label %exit -; CHECK: label="W:200" +; CHECK: label="99.50%" ; CHECK-NOT: ["]; exit: ; preds = %entry, %if ret void diff --git a/llvm/test/Other/cfg-printer-branch-weights.ll b/llvm/test/Other/cfg-printer-branch-weights.ll --- 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 @@ %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 --- /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}