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