1 //===- MachineCFGPrinter.cpp - DOT Printer for Machine Functions ----------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the `-dot-machine-cfg` analysis pass, which emits
11 // Machine Function in DOT format in file titled `<prefix>.<function-name>.dot.
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/CodeGen/MachineCFGPrinter.h"
15 #include "llvm/CodeGen/MachineBasicBlock.h"
16 #include "llvm/CodeGen/MachineFunctionPass.h"
17 #include "llvm/CodeGen/TargetSubtargetInfo.h"
18 #include "llvm/InitializePasses.h"
19 #include "llvm/Pass.h"
20 #include "llvm/PassRegistry.h"
21 #include "llvm/Support/GraphWriter.h"
22 
23 using namespace llvm;
24 
25 #define DEBUG_TYPE "dot-machine-cfg"
26 
27 static cl::opt<std::string>
28     MCFGFuncName("mcfg-func-name", cl::Hidden,
29                  cl::desc("The name of a function (or its substring)"
30                           " whose CFG is viewed/printed."));
31 
32 static cl::opt<std::string> MCFGDotFilenamePrefix(
33     "mcfg-dot-filename-prefix", cl::Hidden,
34     cl::desc("The prefix used for the Machine CFG dot file names."));
35 
36 static cl::opt<bool>
37     CFGOnly("dot-mcfg-only", cl::init(false), cl::Hidden,
38             cl::desc("Print only the CFG without blocks body"));
39 
40 static void writeMCFGToDotFile(MachineFunction &MF) {
41   std::string Filename =
42       (MCFGDotFilenamePrefix + "." + MF.getName() + ".dot").str();
43   errs() << "Writing '" << Filename << "'...";
44 
45   std::error_code EC;
46   raw_fd_ostream File(Filename, EC, sys::fs::OF_Text);
47 
48   DOTMachineFuncInfo MCFGInfo(&MF);
49 
50   if (!EC)
51     WriteGraph(File, &MCFGInfo, CFGOnly);
52   else
53     errs() << "  error opening file for writing!";
54   errs() << '\n';
55 }
56 
57 namespace {
58 
59 class MachineCFGPrinter : public MachineFunctionPass {
60 public:
61   static char ID;
62 
63   MachineCFGPrinter();
64 
65   bool runOnMachineFunction(MachineFunction &MF) override;
66 
67   void getAnalysisUsage(AnalysisUsage &AU) const override {
68     AU.setPreservesCFG();
69     MachineFunctionPass::getAnalysisUsage(AU);
70   }
71 };
72 
73 } // namespace
74 
75 char MachineCFGPrinter::ID = 0;
76 
77 char &llvm::MachineCFGPrinterID = MachineCFGPrinter::ID;
78 
79 INITIALIZE_PASS(MachineCFGPrinter, DEBUG_TYPE, "Machine CFG Printer Pass",
80                 false, true)
81 
82 /// Default construct and initialize the pass.
83 MachineCFGPrinter::MachineCFGPrinter() : MachineFunctionPass(ID) {
84   initializeMachineCFGPrinterPass(*PassRegistry::getPassRegistry());
85 }
86 
87 bool MachineCFGPrinter::runOnMachineFunction(MachineFunction &MF) {
88   if (!MCFGFuncName.empty() && !MF.getName().contains(MCFGFuncName))
89     return false;
90   errs() << "Writing Machine CFG for function ";
91   errs().write_escaped(MF.getName()) << '\n';
92 
93   writeMCFGToDotFile(MF);
94   return false;
95 }
96