17330f729Sjoerg //===- RegionPrinter.cpp - Print regions tree pass ------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg // Print out the region tree of a function using dotty/graphviz.
97330f729Sjoerg //===----------------------------------------------------------------------===//
107330f729Sjoerg
117330f729Sjoerg #include "llvm/Analysis/RegionPrinter.h"
127330f729Sjoerg #include "llvm/ADT/DepthFirstIterator.h"
137330f729Sjoerg #include "llvm/ADT/PostOrderIterator.h"
147330f729Sjoerg #include "llvm/ADT/Statistic.h"
157330f729Sjoerg #include "llvm/Analysis/DOTGraphTraitsPass.h"
167330f729Sjoerg #include "llvm/Analysis/Passes.h"
177330f729Sjoerg #include "llvm/Analysis/RegionInfo.h"
187330f729Sjoerg #include "llvm/Analysis/RegionIterator.h"
19*82d56013Sjoerg #include "llvm/InitializePasses.h"
207330f729Sjoerg #include "llvm/Support/CommandLine.h"
217330f729Sjoerg #include "llvm/Support/Debug.h"
227330f729Sjoerg #include "llvm/Support/raw_ostream.h"
237330f729Sjoerg #ifndef NDEBUG
247330f729Sjoerg #include "llvm/IR/LegacyPassManager.h"
257330f729Sjoerg #endif
267330f729Sjoerg
277330f729Sjoerg using namespace llvm;
287330f729Sjoerg
297330f729Sjoerg //===----------------------------------------------------------------------===//
307330f729Sjoerg /// onlySimpleRegion - Show only the simple regions in the RegionViewer.
317330f729Sjoerg static cl::opt<bool>
327330f729Sjoerg onlySimpleRegions("only-simple-regions",
337330f729Sjoerg cl::desc("Show only simple regions in the graphviz viewer"),
347330f729Sjoerg cl::Hidden,
357330f729Sjoerg cl::init(false));
367330f729Sjoerg
377330f729Sjoerg namespace llvm {
387330f729Sjoerg template<>
397330f729Sjoerg struct DOTGraphTraits<RegionNode*> : public DefaultDOTGraphTraits {
407330f729Sjoerg
DOTGraphTraitsllvm::DOTGraphTraits417330f729Sjoerg DOTGraphTraits (bool isSimple=false)
427330f729Sjoerg : DefaultDOTGraphTraits(isSimple) {}
437330f729Sjoerg
getNodeLabelllvm::DOTGraphTraits447330f729Sjoerg std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) {
457330f729Sjoerg
467330f729Sjoerg if (!Node->isSubRegion()) {
477330f729Sjoerg BasicBlock *BB = Node->getNodeAs<BasicBlock>();
487330f729Sjoerg
497330f729Sjoerg if (isSimple())
50*82d56013Sjoerg return DOTGraphTraits<DOTFuncInfo *>
51*82d56013Sjoerg ::getSimpleNodeLabel(BB, nullptr);
527330f729Sjoerg else
53*82d56013Sjoerg return DOTGraphTraits<DOTFuncInfo *>
54*82d56013Sjoerg ::getCompleteNodeLabel(BB, nullptr);
557330f729Sjoerg }
567330f729Sjoerg
577330f729Sjoerg return "Not implemented";
587330f729Sjoerg }
597330f729Sjoerg };
607330f729Sjoerg
617330f729Sjoerg template <>
627330f729Sjoerg struct DOTGraphTraits<RegionInfo *> : public DOTGraphTraits<RegionNode *> {
637330f729Sjoerg
DOTGraphTraitsllvm::DOTGraphTraits647330f729Sjoerg DOTGraphTraits (bool isSimple = false)
657330f729Sjoerg : DOTGraphTraits<RegionNode*>(isSimple) {}
667330f729Sjoerg
getGraphNamellvm::DOTGraphTraits677330f729Sjoerg static std::string getGraphName(const RegionInfo *) { return "Region Graph"; }
687330f729Sjoerg
getNodeLabelllvm::DOTGraphTraits697330f729Sjoerg std::string getNodeLabel(RegionNode *Node, RegionInfo *G) {
707330f729Sjoerg return DOTGraphTraits<RegionNode *>::getNodeLabel(
717330f729Sjoerg Node, reinterpret_cast<RegionNode *>(G->getTopLevelRegion()));
727330f729Sjoerg }
737330f729Sjoerg
getEdgeAttributesllvm::DOTGraphTraits747330f729Sjoerg std::string getEdgeAttributes(RegionNode *srcNode,
757330f729Sjoerg GraphTraits<RegionInfo *>::ChildIteratorType CI,
767330f729Sjoerg RegionInfo *G) {
777330f729Sjoerg RegionNode *destNode = *CI;
787330f729Sjoerg
797330f729Sjoerg if (srcNode->isSubRegion() || destNode->isSubRegion())
807330f729Sjoerg return "";
817330f729Sjoerg
827330f729Sjoerg // In case of a backedge, do not use it to define the layout of the nodes.
837330f729Sjoerg BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>();
847330f729Sjoerg BasicBlock *destBB = destNode->getNodeAs<BasicBlock>();
857330f729Sjoerg
867330f729Sjoerg Region *R = G->getRegionFor(destBB);
877330f729Sjoerg
887330f729Sjoerg while (R && R->getParent())
897330f729Sjoerg if (R->getParent()->getEntry() == destBB)
907330f729Sjoerg R = R->getParent();
917330f729Sjoerg else
927330f729Sjoerg break;
937330f729Sjoerg
947330f729Sjoerg if (R && R->getEntry() == destBB && R->contains(srcBB))
957330f729Sjoerg return "constraint=false";
967330f729Sjoerg
977330f729Sjoerg return "";
987330f729Sjoerg }
997330f729Sjoerg
1007330f729Sjoerg // Print the cluster of the subregions. This groups the single basic blocks
1017330f729Sjoerg // and adds a different background color for each group.
printRegionClusterllvm::DOTGraphTraits1027330f729Sjoerg static void printRegionCluster(const Region &R, GraphWriter<RegionInfo *> &GW,
1037330f729Sjoerg unsigned depth = 0) {
1047330f729Sjoerg raw_ostream &O = GW.getOStream();
1057330f729Sjoerg O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void*>(&R)
1067330f729Sjoerg << " {\n";
1077330f729Sjoerg O.indent(2 * (depth + 1)) << "label = \"\";\n";
1087330f729Sjoerg
1097330f729Sjoerg if (!onlySimpleRegions || R.isSimple()) {
1107330f729Sjoerg O.indent(2 * (depth + 1)) << "style = filled;\n";
1117330f729Sjoerg O.indent(2 * (depth + 1)) << "color = "
1127330f729Sjoerg << ((R.getDepth() * 2 % 12) + 1) << "\n";
1137330f729Sjoerg
1147330f729Sjoerg } else {
1157330f729Sjoerg O.indent(2 * (depth + 1)) << "style = solid;\n";
1167330f729Sjoerg O.indent(2 * (depth + 1)) << "color = "
1177330f729Sjoerg << ((R.getDepth() * 2 % 12) + 2) << "\n";
1187330f729Sjoerg }
1197330f729Sjoerg
1207330f729Sjoerg for (const auto &RI : R)
1217330f729Sjoerg printRegionCluster(*RI, GW, depth + 1);
1227330f729Sjoerg
1237330f729Sjoerg const RegionInfo &RI = *static_cast<const RegionInfo*>(R.getRegionInfo());
1247330f729Sjoerg
1257330f729Sjoerg for (auto *BB : R.blocks())
1267330f729Sjoerg if (RI.getRegionFor(BB) == &R)
1277330f729Sjoerg O.indent(2 * (depth + 1)) << "Node"
1287330f729Sjoerg << static_cast<const void*>(RI.getTopLevelRegion()->getBBNode(BB))
1297330f729Sjoerg << ";\n";
1307330f729Sjoerg
1317330f729Sjoerg O.indent(2 * depth) << "}\n";
1327330f729Sjoerg }
1337330f729Sjoerg
addCustomGraphFeaturesllvm::DOTGraphTraits1347330f729Sjoerg static void addCustomGraphFeatures(const RegionInfo *G,
1357330f729Sjoerg GraphWriter<RegionInfo *> &GW) {
1367330f729Sjoerg raw_ostream &O = GW.getOStream();
1377330f729Sjoerg O << "\tcolorscheme = \"paired12\"\n";
1387330f729Sjoerg printRegionCluster(*G->getTopLevelRegion(), GW, 4);
1397330f729Sjoerg }
1407330f729Sjoerg };
1417330f729Sjoerg } //end namespace llvm
1427330f729Sjoerg
1437330f729Sjoerg namespace {
1447330f729Sjoerg
1457330f729Sjoerg struct RegionInfoPassGraphTraits {
getGraph__anonf49763360111::RegionInfoPassGraphTraits1467330f729Sjoerg static RegionInfo *getGraph(RegionInfoPass *RIP) {
1477330f729Sjoerg return &RIP->getRegionInfo();
1487330f729Sjoerg }
1497330f729Sjoerg };
1507330f729Sjoerg
1517330f729Sjoerg struct RegionPrinter
1527330f729Sjoerg : public DOTGraphTraitsPrinter<RegionInfoPass, false, RegionInfo *,
1537330f729Sjoerg RegionInfoPassGraphTraits> {
1547330f729Sjoerg static char ID;
RegionPrinter__anonf49763360111::RegionPrinter1557330f729Sjoerg RegionPrinter()
1567330f729Sjoerg : DOTGraphTraitsPrinter<RegionInfoPass, false, RegionInfo *,
1577330f729Sjoerg RegionInfoPassGraphTraits>("reg", ID) {
1587330f729Sjoerg initializeRegionPrinterPass(*PassRegistry::getPassRegistry());
1597330f729Sjoerg }
1607330f729Sjoerg };
1617330f729Sjoerg char RegionPrinter::ID = 0;
1627330f729Sjoerg
1637330f729Sjoerg struct RegionOnlyPrinter
1647330f729Sjoerg : public DOTGraphTraitsPrinter<RegionInfoPass, true, RegionInfo *,
1657330f729Sjoerg RegionInfoPassGraphTraits> {
1667330f729Sjoerg static char ID;
RegionOnlyPrinter__anonf49763360111::RegionOnlyPrinter1677330f729Sjoerg RegionOnlyPrinter()
1687330f729Sjoerg : DOTGraphTraitsPrinter<RegionInfoPass, true, RegionInfo *,
1697330f729Sjoerg RegionInfoPassGraphTraits>("reg", ID) {
1707330f729Sjoerg initializeRegionOnlyPrinterPass(*PassRegistry::getPassRegistry());
1717330f729Sjoerg }
1727330f729Sjoerg };
1737330f729Sjoerg char RegionOnlyPrinter::ID = 0;
1747330f729Sjoerg
1757330f729Sjoerg struct RegionViewer
1767330f729Sjoerg : public DOTGraphTraitsViewer<RegionInfoPass, false, RegionInfo *,
1777330f729Sjoerg RegionInfoPassGraphTraits> {
1787330f729Sjoerg static char ID;
RegionViewer__anonf49763360111::RegionViewer1797330f729Sjoerg RegionViewer()
1807330f729Sjoerg : DOTGraphTraitsViewer<RegionInfoPass, false, RegionInfo *,
1817330f729Sjoerg RegionInfoPassGraphTraits>("reg", ID) {
1827330f729Sjoerg initializeRegionViewerPass(*PassRegistry::getPassRegistry());
1837330f729Sjoerg }
1847330f729Sjoerg };
1857330f729Sjoerg char RegionViewer::ID = 0;
1867330f729Sjoerg
1877330f729Sjoerg struct RegionOnlyViewer
1887330f729Sjoerg : public DOTGraphTraitsViewer<RegionInfoPass, true, RegionInfo *,
1897330f729Sjoerg RegionInfoPassGraphTraits> {
1907330f729Sjoerg static char ID;
RegionOnlyViewer__anonf49763360111::RegionOnlyViewer1917330f729Sjoerg RegionOnlyViewer()
1927330f729Sjoerg : DOTGraphTraitsViewer<RegionInfoPass, true, RegionInfo *,
1937330f729Sjoerg RegionInfoPassGraphTraits>("regonly", ID) {
1947330f729Sjoerg initializeRegionOnlyViewerPass(*PassRegistry::getPassRegistry());
1957330f729Sjoerg }
1967330f729Sjoerg };
1977330f729Sjoerg char RegionOnlyViewer::ID = 0;
1987330f729Sjoerg
1997330f729Sjoerg } //end anonymous namespace
2007330f729Sjoerg
2017330f729Sjoerg INITIALIZE_PASS(RegionPrinter, "dot-regions",
2027330f729Sjoerg "Print regions of function to 'dot' file", true, true)
2037330f729Sjoerg
2047330f729Sjoerg INITIALIZE_PASS(
2057330f729Sjoerg RegionOnlyPrinter, "dot-regions-only",
2067330f729Sjoerg "Print regions of function to 'dot' file (with no function bodies)", true,
2077330f729Sjoerg true)
2087330f729Sjoerg
2097330f729Sjoerg INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function",
2107330f729Sjoerg true, true)
2117330f729Sjoerg
2127330f729Sjoerg INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only",
2137330f729Sjoerg "View regions of function (with no function bodies)",
2147330f729Sjoerg true, true)
2157330f729Sjoerg
createRegionPrinterPass()2167330f729Sjoerg FunctionPass *llvm::createRegionPrinterPass() { return new RegionPrinter(); }
2177330f729Sjoerg
createRegionOnlyPrinterPass()2187330f729Sjoerg FunctionPass *llvm::createRegionOnlyPrinterPass() {
2197330f729Sjoerg return new RegionOnlyPrinter();
2207330f729Sjoerg }
2217330f729Sjoerg
createRegionViewerPass()2227330f729Sjoerg FunctionPass* llvm::createRegionViewerPass() {
2237330f729Sjoerg return new RegionViewer();
2247330f729Sjoerg }
2257330f729Sjoerg
createRegionOnlyViewerPass()2267330f729Sjoerg FunctionPass* llvm::createRegionOnlyViewerPass() {
2277330f729Sjoerg return new RegionOnlyViewer();
2287330f729Sjoerg }
2297330f729Sjoerg
2307330f729Sjoerg #ifndef NDEBUG
viewRegionInfo(RegionInfo * RI,bool ShortNames)2317330f729Sjoerg static void viewRegionInfo(RegionInfo *RI, bool ShortNames) {
2327330f729Sjoerg assert(RI && "Argument must be non-null");
2337330f729Sjoerg
2347330f729Sjoerg llvm::Function *F = RI->getTopLevelRegion()->getEntry()->getParent();
2357330f729Sjoerg std::string GraphName = DOTGraphTraits<RegionInfo *>::getGraphName(RI);
2367330f729Sjoerg
2377330f729Sjoerg llvm::ViewGraph(RI, "reg", ShortNames,
2387330f729Sjoerg Twine(GraphName) + " for '" + F->getName() + "' function");
2397330f729Sjoerg }
2407330f729Sjoerg
invokeFunctionPass(const Function * F,FunctionPass * ViewerPass)2417330f729Sjoerg static void invokeFunctionPass(const Function *F, FunctionPass *ViewerPass) {
2427330f729Sjoerg assert(F && "Argument must be non-null");
2437330f729Sjoerg assert(!F->isDeclaration() && "Function must have an implementation");
2447330f729Sjoerg
2457330f729Sjoerg // The viewer and analysis passes do not modify anything, so we can safely
2467330f729Sjoerg // remove the const qualifier
2477330f729Sjoerg auto NonConstF = const_cast<Function *>(F);
2487330f729Sjoerg
2497330f729Sjoerg llvm::legacy::FunctionPassManager FPM(NonConstF->getParent());
2507330f729Sjoerg FPM.add(ViewerPass);
2517330f729Sjoerg FPM.doInitialization();
2527330f729Sjoerg FPM.run(*NonConstF);
2537330f729Sjoerg FPM.doFinalization();
2547330f729Sjoerg }
2557330f729Sjoerg
viewRegion(RegionInfo * RI)2567330f729Sjoerg void llvm::viewRegion(RegionInfo *RI) { viewRegionInfo(RI, false); }
2577330f729Sjoerg
viewRegion(const Function * F)2587330f729Sjoerg void llvm::viewRegion(const Function *F) {
2597330f729Sjoerg invokeFunctionPass(F, createRegionViewerPass());
2607330f729Sjoerg }
2617330f729Sjoerg
viewRegionOnly(RegionInfo * RI)2627330f729Sjoerg void llvm::viewRegionOnly(RegionInfo *RI) { viewRegionInfo(RI, true); }
2637330f729Sjoerg
viewRegionOnly(const Function * F)2647330f729Sjoerg void llvm::viewRegionOnly(const Function *F) {
2657330f729Sjoerg invokeFunctionPass(F, createRegionOnlyViewerPass());
2667330f729Sjoerg }
2677330f729Sjoerg #endif
268