aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/CFGPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/CFGPrinter.cpp')
-rw-r--r--llvm/lib/Analysis/CFGPrinter.cpp309
1 files changed, 203 insertions, 106 deletions
diff --git a/llvm/lib/Analysis/CFGPrinter.cpp b/llvm/lib/Analysis/CFGPrinter.cpp
index 88e7d3bdede1..cf4afc8cfd9c 100644
--- a/llvm/lib/Analysis/CFGPrinter.cpp
+++ b/llvm/lib/Analysis/CFGPrinter.cpp
@@ -18,69 +18,135 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/CFGPrinter.h"
+#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
+#include <algorithm>
+
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."));
-namespace {
- struct CFGViewerLegacyPass : public FunctionPass {
- static char ID; // Pass identifcation, replacement for typeid
- CFGViewerLegacyPass() : FunctionPass(ID) {
- initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
- }
+static cl::opt<bool> HideUnreachablePaths("cfg-hide-unreachable-paths",
+ cl::init(false));
- bool runOnFunction(Function &F) override {
- F.viewCFG();
- return false;
- }
+static cl::opt<bool> HideDeoptimizePaths("cfg-hide-deoptimize-paths",
+ cl::init(false));
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
+static cl::opt<bool> ShowHeatColors("cfg-heat-colors", cl::init(true),
+ cl::Hidden,
+ cl::desc("Show heat colors in CFG"));
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- }
- };
-}
+static cl::opt<bool> UseRawEdgeWeight("cfg-raw-weights", cl::init(false),
+ cl::Hidden,
+ cl::desc("Use raw weights for labels. "
+ "Use percentages as default."));
-char CFGViewerLegacyPass::ID = 0;
-INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true)
+static cl::opt<bool>
+ ShowEdgeWeight("cfg-weights", cl::init(false), cl::Hidden,
+ cl::desc("Show edges labeled with weights"));
-PreservedAnalyses CFGViewerPass::run(Function &F,
- FunctionAnalysisManager &AM) {
- F.viewCFG();
- return PreservedAnalyses::all();
+static void writeCFGToDotFile(Function &F, BlockFrequencyInfo *BFI,
+ BranchProbabilityInfo *BPI, uint64_t MaxFreq,
+ bool CFGOnly = false) {
+ std::string Filename =
+ (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str();
+ errs() << "Writing '" << Filename << "'...";
+
+ std::error_code EC;
+ raw_fd_ostream File(Filename, EC, sys::fs::F_Text);
+
+ DOTFuncInfo CFGInfo(&F, BFI, BPI, MaxFreq);
+ CFGInfo.setHeatColors(ShowHeatColors);
+ CFGInfo.setEdgeWeights(ShowEdgeWeight);
+ CFGInfo.setRawEdgeWeights(UseRawEdgeWeight);
+
+ if (!EC)
+ WriteGraph(File, &CFGInfo, CFGOnly);
+ else
+ errs() << " error opening file for writing!";
+ errs() << "\n";
}
+static void viewCFG(Function &F, const BlockFrequencyInfo *BFI,
+ const 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 CFGOnlyViewerLegacyPass : public FunctionPass {
- static char ID; // Pass identifcation, replacement for typeid
- CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
- initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
- }
+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 getAnalysisUsage(AnalysisUsage &AU) const override {
+ FunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<BlockFrequencyInfoWrapperPass>();
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
+ AU.setPreservesAll();
+ }
+};
+}
- bool runOnFunction(Function &F) override {
- F.viewCFGOnly();
- return false;
- }
+char CFGViewerLegacyPass::ID = 0;
+INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false,
+ true)
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
+PreservedAnalyses CFGViewerPass::run(Function &F, FunctionAnalysisManager &AM) {
+ auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
+ auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
+ viewCFG(F, BFI, BPI, getMaxFreq(F, BFI));
+ return PreservedAnalyses::all();
+}
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- }
- };
+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, 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 CFGOnlyViewerLegacyPass::ID = 0;
@@ -89,84 +155,83 @@ INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only",
PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
FunctionAnalysisManager &AM) {
- F.viewCFGOnly();
+ auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
+ auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
+ viewCFG(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
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();
- }
- };
+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 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) {
- writeCFGToDotFile(F);
+ auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
+ auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
+ 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 {
- writeCFGToDotFile(F, /*CFGOnly=*/true);
- return false;
- }
- void print(raw_ostream &OS, const Module* = nullptr) const override {}
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- 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) {
- writeCFGToDotFile(F, /*CFGOnly=*/true);
+ auto *BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
+ auto *BPI = &AM.getResult<BranchProbabilityAnalysis>(F);
+ writeCFGToDotFile(F, BFI, BPI, getMaxFreq(F, BFI), /*CFGOnly=*/true);
return PreservedAnalyses::all();
}
@@ -175,10 +240,14 @@ PreservedAnalyses CFGOnlyPrinterPass::run(Function &F,
/// 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 {
+void Function::viewCFG() const { viewCFG(false, nullptr, nullptr); }
+
+void Function::viewCFG(bool ViewCFGOnly, const BlockFrequencyInfo *BFI,
+ const BranchProbabilityInfo *BPI) const {
if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
- return;
- ViewGraph(this, "cfg" + getName());
+ return;
+ DOTFuncInfo CFGInfo(this, BFI, BPI, BFI ? getMaxFreq(*this, BFI) : 0);
+ ViewGraph(&CFGInfo, "cfg" + getName(), ViewCFGOnly);
}
/// viewCFGOnly - This function is meant for use from the debugger. It works
@@ -186,17 +255,45 @@ void Function::viewCFG() const {
/// 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);
+void Function::viewCFGOnly() const { viewCFGOnly(nullptr, nullptr); }
+
+void Function::viewCFGOnly(const BlockFrequencyInfo *BFI,
+ const BranchProbabilityInfo *BPI) const {
+ viewCFG(true, BFI, BPI);
}
-FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
+FunctionPass *llvm::createCFGPrinterLegacyPassPass() {
return new CFGPrinterLegacyPass();
}
-FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
+FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass() {
return new CFGOnlyPrinterLegacyPass();
}
+void DOTGraphTraits<DOTFuncInfo *>::computeHiddenNodes(const Function *F) {
+ auto evaluateBB = [&](const BasicBlock *Node) {
+ if (succ_begin(Node) == succ_end(Node)) {
+ const Instruction *TI = Node->getTerminator();
+ isHiddenBasicBlock[Node] =
+ (HideUnreachablePaths && isa<UnreachableInst>(TI)) ||
+ (HideDeoptimizePaths && Node->getTerminatingDeoptimizeCall());
+ return;
+ }
+ isHiddenBasicBlock[Node] = std::all_of(
+ succ_begin(Node), succ_end(Node),
+ [this](const BasicBlock *BB) { return isHiddenBasicBlock[BB]; });
+ };
+ /// The post order traversal iteration is done to know the status of
+ /// isHiddenBasicBlock for all the successors on the current BB.
+ for_each(po_begin(&F->getEntryBlock()), po_end(&F->getEntryBlock()),
+ evaluateBB);
+}
+
+bool DOTGraphTraits<DOTFuncInfo *>::isNodeHidden(const BasicBlock *Node) {
+ // If both restricting flags are false, all nodes are displayed.
+ if (!HideUnreachablePaths && !HideDeoptimizePaths)
+ return false;
+ if (isHiddenBasicBlock.find(Node) == isHiddenBasicBlock.end())
+ computeHiddenNodes(Node->getParent());
+ return isHiddenBasicBlock[Node];
+}