xref: /freebsd-src/contrib/llvm-project/llvm/lib/Analysis/RegionPrinter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- RegionPrinter.cpp - Print regions tree pass ------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric // Print out the region tree of a function using dotty/graphviz.
90b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/Analysis/RegionPrinter.h"
120b57cec5SDimitry Andric #include "llvm/Analysis/DOTGraphTraitsPass.h"
130b57cec5SDimitry Andric #include "llvm/Analysis/RegionInfo.h"
140b57cec5SDimitry Andric #include "llvm/Analysis/RegionIterator.h"
15480093f4SDimitry Andric #include "llvm/InitializePasses.h"
160b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
170b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
180b57cec5SDimitry Andric #ifndef NDEBUG
190b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
200b57cec5SDimitry Andric #endif
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
250b57cec5SDimitry Andric /// onlySimpleRegion - Show only the simple regions in the RegionViewer.
260b57cec5SDimitry Andric static cl::opt<bool>
270b57cec5SDimitry Andric onlySimpleRegions("only-simple-regions",
280b57cec5SDimitry Andric                   cl::desc("Show only simple regions in the graphviz viewer"),
290b57cec5SDimitry Andric                   cl::Hidden,
300b57cec5SDimitry Andric                   cl::init(false));
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric namespace llvm {
330b57cec5SDimitry Andric 
getNodeLabel(RegionNode * Node,RegionNode * Graph)34*81ad6265SDimitry Andric std::string DOTGraphTraits<RegionNode *>::getNodeLabel(RegionNode *Node,
35*81ad6265SDimitry Andric                                                        RegionNode *Graph) {
360b57cec5SDimitry Andric   if (!Node->isSubRegion()) {
370b57cec5SDimitry Andric     BasicBlock *BB = Node->getNodeAs<BasicBlock>();
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric     if (isSimple())
40*81ad6265SDimitry Andric       return DOTGraphTraits<DOTFuncInfo *>::getSimpleNodeLabel(BB, nullptr);
410b57cec5SDimitry Andric     else
42*81ad6265SDimitry Andric       return DOTGraphTraits<DOTFuncInfo *>::getCompleteNodeLabel(BB, nullptr);
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   return "Not implemented";
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric template <>
490b57cec5SDimitry Andric struct DOTGraphTraits<RegionInfo *> : public DOTGraphTraits<RegionNode *> {
500b57cec5SDimitry Andric 
DOTGraphTraitsllvm::DOTGraphTraits510b57cec5SDimitry Andric   DOTGraphTraits (bool isSimple = false)
520b57cec5SDimitry Andric     : DOTGraphTraits<RegionNode*>(isSimple) {}
530b57cec5SDimitry Andric 
getGraphNamellvm::DOTGraphTraits540b57cec5SDimitry Andric   static std::string getGraphName(const RegionInfo *) { return "Region Graph"; }
550b57cec5SDimitry Andric 
getNodeLabelllvm::DOTGraphTraits560b57cec5SDimitry Andric   std::string getNodeLabel(RegionNode *Node, RegionInfo *G) {
570b57cec5SDimitry Andric     return DOTGraphTraits<RegionNode *>::getNodeLabel(
580b57cec5SDimitry Andric         Node, reinterpret_cast<RegionNode *>(G->getTopLevelRegion()));
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric 
getEdgeAttributesllvm::DOTGraphTraits610b57cec5SDimitry Andric   std::string getEdgeAttributes(RegionNode *srcNode,
620b57cec5SDimitry Andric                                 GraphTraits<RegionInfo *>::ChildIteratorType CI,
630b57cec5SDimitry Andric                                 RegionInfo *G) {
640b57cec5SDimitry Andric     RegionNode *destNode = *CI;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric     if (srcNode->isSubRegion() || destNode->isSubRegion())
670b57cec5SDimitry Andric       return "";
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric     // In case of a backedge, do not use it to define the layout of the nodes.
700b57cec5SDimitry Andric     BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>();
710b57cec5SDimitry Andric     BasicBlock *destBB = destNode->getNodeAs<BasicBlock>();
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric     Region *R = G->getRegionFor(destBB);
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric     while (R && R->getParent())
760b57cec5SDimitry Andric       if (R->getParent()->getEntry() == destBB)
770b57cec5SDimitry Andric         R = R->getParent();
780b57cec5SDimitry Andric       else
790b57cec5SDimitry Andric         break;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric     if (R && R->getEntry() == destBB && R->contains(srcBB))
820b57cec5SDimitry Andric       return "constraint=false";
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric     return "";
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   // Print the cluster of the subregions. This groups the single basic blocks
880b57cec5SDimitry Andric   // and adds a different background color for each group.
printRegionClusterllvm::DOTGraphTraits890b57cec5SDimitry Andric   static void printRegionCluster(const Region &R, GraphWriter<RegionInfo *> &GW,
900b57cec5SDimitry Andric                                  unsigned depth = 0) {
910b57cec5SDimitry Andric     raw_ostream &O = GW.getOStream();
920b57cec5SDimitry Andric     O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void*>(&R)
930b57cec5SDimitry Andric       << " {\n";
940b57cec5SDimitry Andric     O.indent(2 * (depth + 1)) << "label = \"\";\n";
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     if (!onlySimpleRegions || R.isSimple()) {
970b57cec5SDimitry Andric       O.indent(2 * (depth + 1)) << "style = filled;\n";
980b57cec5SDimitry Andric       O.indent(2 * (depth + 1)) << "color = "
990b57cec5SDimitry Andric         << ((R.getDepth() * 2 % 12) + 1) << "\n";
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     } else {
1020b57cec5SDimitry Andric       O.indent(2 * (depth + 1)) << "style = solid;\n";
1030b57cec5SDimitry Andric       O.indent(2 * (depth + 1)) << "color = "
1040b57cec5SDimitry Andric         << ((R.getDepth() * 2 % 12) + 2) << "\n";
1050b57cec5SDimitry Andric     }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric     for (const auto &RI : R)
1080b57cec5SDimitry Andric       printRegionCluster(*RI, GW, depth + 1);
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric     const RegionInfo &RI = *static_cast<const RegionInfo*>(R.getRegionInfo());
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric     for (auto *BB : R.blocks())
1130b57cec5SDimitry Andric       if (RI.getRegionFor(BB) == &R)
1140b57cec5SDimitry Andric         O.indent(2 * (depth + 1)) << "Node"
1150b57cec5SDimitry Andric           << static_cast<const void*>(RI.getTopLevelRegion()->getBBNode(BB))
1160b57cec5SDimitry Andric           << ";\n";
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric     O.indent(2 * depth) << "}\n";
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
addCustomGraphFeaturesllvm::DOTGraphTraits1210b57cec5SDimitry Andric   static void addCustomGraphFeatures(const RegionInfo *G,
1220b57cec5SDimitry Andric                                      GraphWriter<RegionInfo *> &GW) {
1230b57cec5SDimitry Andric     raw_ostream &O = GW.getOStream();
1240b57cec5SDimitry Andric     O << "\tcolorscheme = \"paired12\"\n";
1250b57cec5SDimitry Andric     printRegionCluster(*G->getTopLevelRegion(), GW, 4);
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric };
1280b57cec5SDimitry Andric } // end namespace llvm
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric namespace {
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric struct RegionInfoPassGraphTraits {
getGraph__anon4a51f5fd0111::RegionInfoPassGraphTraits1330b57cec5SDimitry Andric   static RegionInfo *getGraph(RegionInfoPass *RIP) {
1340b57cec5SDimitry Andric     return &RIP->getRegionInfo();
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric };
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric struct RegionPrinter
139*81ad6265SDimitry Andric     : public DOTGraphTraitsPrinterWrapperPass<
140*81ad6265SDimitry Andric           RegionInfoPass, false, RegionInfo *, RegionInfoPassGraphTraits> {
1410b57cec5SDimitry Andric   static char ID;
RegionPrinter__anon4a51f5fd0111::RegionPrinter1420b57cec5SDimitry Andric   RegionPrinter()
143*81ad6265SDimitry Andric       : DOTGraphTraitsPrinterWrapperPass<RegionInfoPass, false, RegionInfo *,
1440b57cec5SDimitry Andric                                          RegionInfoPassGraphTraits>("reg", ID) {
1450b57cec5SDimitry Andric     initializeRegionPrinterPass(*PassRegistry::getPassRegistry());
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric };
1480b57cec5SDimitry Andric char RegionPrinter::ID = 0;
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric struct RegionOnlyPrinter
151*81ad6265SDimitry Andric     : public DOTGraphTraitsPrinterWrapperPass<
152*81ad6265SDimitry Andric           RegionInfoPass, true, RegionInfo *, RegionInfoPassGraphTraits> {
1530b57cec5SDimitry Andric   static char ID;
RegionOnlyPrinter__anon4a51f5fd0111::RegionOnlyPrinter1540b57cec5SDimitry Andric   RegionOnlyPrinter()
155*81ad6265SDimitry Andric       : DOTGraphTraitsPrinterWrapperPass<RegionInfoPass, true, RegionInfo *,
1560b57cec5SDimitry Andric                                          RegionInfoPassGraphTraits>("reg", ID) {
1570b57cec5SDimitry Andric     initializeRegionOnlyPrinterPass(*PassRegistry::getPassRegistry());
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric };
1600b57cec5SDimitry Andric char RegionOnlyPrinter::ID = 0;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric struct RegionViewer
163*81ad6265SDimitry Andric     : public DOTGraphTraitsViewerWrapperPass<
164*81ad6265SDimitry Andric           RegionInfoPass, false, RegionInfo *, RegionInfoPassGraphTraits> {
1650b57cec5SDimitry Andric   static char ID;
RegionViewer__anon4a51f5fd0111::RegionViewer1660b57cec5SDimitry Andric   RegionViewer()
167*81ad6265SDimitry Andric       : DOTGraphTraitsViewerWrapperPass<RegionInfoPass, false, RegionInfo *,
1680b57cec5SDimitry Andric                                         RegionInfoPassGraphTraits>("reg", ID) {
1690b57cec5SDimitry Andric     initializeRegionViewerPass(*PassRegistry::getPassRegistry());
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric };
1720b57cec5SDimitry Andric char RegionViewer::ID = 0;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric struct RegionOnlyViewer
175*81ad6265SDimitry Andric     : public DOTGraphTraitsViewerWrapperPass<RegionInfoPass, true, RegionInfo *,
1760b57cec5SDimitry Andric                                              RegionInfoPassGraphTraits> {
1770b57cec5SDimitry Andric   static char ID;
RegionOnlyViewer__anon4a51f5fd0111::RegionOnlyViewer1780b57cec5SDimitry Andric   RegionOnlyViewer()
179*81ad6265SDimitry Andric       : DOTGraphTraitsViewerWrapperPass<RegionInfoPass, true, RegionInfo *,
180*81ad6265SDimitry Andric                                         RegionInfoPassGraphTraits>("regonly",
181*81ad6265SDimitry Andric                                                                    ID) {
1820b57cec5SDimitry Andric     initializeRegionOnlyViewerPass(*PassRegistry::getPassRegistry());
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric };
1850b57cec5SDimitry Andric char RegionOnlyViewer::ID = 0;
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric } //end anonymous namespace
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric INITIALIZE_PASS(RegionPrinter, "dot-regions",
1900b57cec5SDimitry Andric                 "Print regions of function to 'dot' file", true, true)
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric INITIALIZE_PASS(
1930b57cec5SDimitry Andric     RegionOnlyPrinter, "dot-regions-only",
1940b57cec5SDimitry Andric     "Print regions of function to 'dot' file (with no function bodies)", true,
1950b57cec5SDimitry Andric     true)
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function",
1980b57cec5SDimitry Andric                 true, true)
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only",
2010b57cec5SDimitry Andric                 "View regions of function (with no function bodies)",
2020b57cec5SDimitry Andric                 true, true)
2030b57cec5SDimitry Andric 
createRegionPrinterPass()2040b57cec5SDimitry Andric FunctionPass *llvm::createRegionPrinterPass() { return new RegionPrinter(); }
2050b57cec5SDimitry Andric 
createRegionOnlyPrinterPass()2060b57cec5SDimitry Andric FunctionPass *llvm::createRegionOnlyPrinterPass() {
2070b57cec5SDimitry Andric   return new RegionOnlyPrinter();
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
createRegionViewerPass()2100b57cec5SDimitry Andric FunctionPass* llvm::createRegionViewerPass() {
2110b57cec5SDimitry Andric   return new RegionViewer();
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
createRegionOnlyViewerPass()2140b57cec5SDimitry Andric FunctionPass* llvm::createRegionOnlyViewerPass() {
2150b57cec5SDimitry Andric   return new RegionOnlyViewer();
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric #ifndef NDEBUG
viewRegionInfo(RegionInfo * RI,bool ShortNames)2190b57cec5SDimitry Andric static void viewRegionInfo(RegionInfo *RI, bool ShortNames) {
2200b57cec5SDimitry Andric   assert(RI && "Argument must be non-null");
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   llvm::Function *F = RI->getTopLevelRegion()->getEntry()->getParent();
2230b57cec5SDimitry Andric   std::string GraphName = DOTGraphTraits<RegionInfo *>::getGraphName(RI);
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   llvm::ViewGraph(RI, "reg", ShortNames,
2260b57cec5SDimitry Andric                   Twine(GraphName) + " for '" + F->getName() + "' function");
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
invokeFunctionPass(const Function * F,FunctionPass * ViewerPass)2290b57cec5SDimitry Andric static void invokeFunctionPass(const Function *F, FunctionPass *ViewerPass) {
2300b57cec5SDimitry Andric   assert(F && "Argument must be non-null");
2310b57cec5SDimitry Andric   assert(!F->isDeclaration() && "Function must have an implementation");
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   // The viewer and analysis passes do not modify anything, so we can safely
2340b57cec5SDimitry Andric   // remove the const qualifier
2350b57cec5SDimitry Andric   auto NonConstF = const_cast<Function *>(F);
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   llvm::legacy::FunctionPassManager FPM(NonConstF->getParent());
2380b57cec5SDimitry Andric   FPM.add(ViewerPass);
2390b57cec5SDimitry Andric   FPM.doInitialization();
2400b57cec5SDimitry Andric   FPM.run(*NonConstF);
2410b57cec5SDimitry Andric   FPM.doFinalization();
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
viewRegion(RegionInfo * RI)2440b57cec5SDimitry Andric void llvm::viewRegion(RegionInfo *RI) { viewRegionInfo(RI, false); }
2450b57cec5SDimitry Andric 
viewRegion(const Function * F)2460b57cec5SDimitry Andric void llvm::viewRegion(const Function *F) {
2470b57cec5SDimitry Andric   invokeFunctionPass(F, createRegionViewerPass());
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric 
viewRegionOnly(RegionInfo * RI)2500b57cec5SDimitry Andric void llvm::viewRegionOnly(RegionInfo *RI) { viewRegionInfo(RI, true); }
2510b57cec5SDimitry Andric 
viewRegionOnly(const Function * F)2520b57cec5SDimitry Andric void llvm::viewRegionOnly(const Function *F) {
2530b57cec5SDimitry Andric   invokeFunctionPass(F, createRegionOnlyViewerPass());
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric #endif
256