Index: polly/include/polly/LinkAllPasses.h =================================================================== --- polly/include/polly/LinkAllPasses.h +++ polly/include/polly/LinkAllPasses.h @@ -35,10 +35,6 @@ llvm::Pass *createDependenceInfoWrapperPassPass(); llvm::Pass * createDependenceInfoPrinterLegacyFunctionPass(llvm::raw_ostream &OS); -llvm::Pass *createDOTOnlyPrinterPass(); -llvm::Pass *createDOTOnlyViewerPass(); -llvm::Pass *createDOTPrinterPass(); -llvm::Pass *createDOTViewerPass(); llvm::Pass *createJSONExporterPass(); llvm::Pass *createJSONImporterPass(); llvm::Pass *createJSONImporterPrinterLegacyPass(llvm::raw_ostream &OS); @@ -94,10 +90,6 @@ polly::createDependenceInfoPrinterLegacyPass(llvm::outs()); polly::createDependenceInfoWrapperPassPass(); polly::createDependenceInfoPrinterLegacyFunctionPass(llvm::outs()); - polly::createDOTOnlyPrinterPass(); - polly::createDOTOnlyViewerPass(); - polly::createDOTPrinterPass(); - polly::createDOTViewerPass(); polly::createJSONExporterPass(); polly::createJSONImporterPass(); polly::createJSONImporterPrinterLegacyPass(llvm::outs()); Index: polly/include/polly/ScopGraphPrinter.h =================================================================== --- /dev/null +++ polly/include/polly/ScopGraphPrinter.h @@ -0,0 +1,99 @@ +//===- GraphPrinter.h - Create a DOT output describing the Scop. ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Create a DOT output describing the Scop. +// +// For each function a dot file is created that shows the control flow graph of +// the function and highlights the detected Scops. +// +//===----------------------------------------------------------------------===// + +#ifndef POLLY_SCOP_GRAPH_PRINTER_H +#define POLLY_SCOP_GRAPH_PRINTER_H + +#include "polly/ScopDetection.h" +#include "polly/Support/ScopLocation.h" +#include "llvm/Analysis/DOTGraphTraitsPass.h" +#include "llvm/Analysis/RegionInfo.h" +#include "llvm/Analysis/RegionIterator.h" +#include "llvm/IR/PassManager.h" + +using namespace polly; +using namespace llvm; + +namespace llvm { + +template <> +struct GraphTraits : public GraphTraits { + static NodeRef getEntryNode(const ScopDetection &SD) { + return GraphTraits::getEntryNode(SD.getRI()); + } + static nodes_iterator nodes_begin(const ScopDetection &SD) { + return nodes_iterator::begin(getEntryNode(SD)); + } + static nodes_iterator nodes_end(const ScopDetection &SD) { + return nodes_iterator::end(getEntryNode(SD)); + } +}; + +template <> struct DOTGraphTraits : public DefaultDOTGraphTraits { + DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} + + std::string getNodeLabel(RegionNode *Node, RegionNode *Graph); +}; + +template <> +struct DOTGraphTraits : public DOTGraphTraits { + DOTGraphTraits(bool isSimple = false) + : DOTGraphTraits(isSimple) {} + static std::string getGraphName(ScopDetection *SD) { return "Scop Graph"; } + + std::string getEdgeAttributes(RegionNode *srcNode, + GraphTraits::ChildIteratorType CI, + ScopDetection *SD); + + std::string getNodeLabel(RegionNode *Node, ScopDetection *SD) { + return DOTGraphTraits::getNodeLabel( + Node, reinterpret_cast(SD->getRI()->getTopLevelRegion())); + } + + static std::string escapeString(std::string String); + + // Print the cluster of the subregions. This groups the single basic blocks + // and adds a different background color for each group. + static void printRegionCluster(ScopDetection *SD, const Region *R, + raw_ostream &O, unsigned depth); + + static void addCustomGraphFeatures(ScopDetection *SD, + GraphWriter &GW); +}; +} // end namespace llvm + +namespace polly { + +struct ScopViewer : public DOTGraphTraitsViewer { + ScopViewer() : DOTGraphTraitsViewer("scops") {} + + bool processFunction(Function &F, const ScopDetection &SD) override; +}; + +struct ScopOnlyViewer : public DOTGraphTraitsViewer { + ScopOnlyViewer() : DOTGraphTraitsViewer("scops-only") {} +}; + +struct ScopPrinter : public DOTGraphTraitsPrinter { + ScopPrinter() : DOTGraphTraitsPrinter("scops") {} +}; + +struct ScopOnlyPrinter : public DOTGraphTraitsPrinter { + ScopOnlyPrinter() : DOTGraphTraitsPrinter("scopsonly") {} +}; + +} // end namespace polly + +#endif /* POLLY_SCOP_GRAPH_PRINTER_H */ Index: polly/lib/Analysis/ScopGraphPrinter.cpp =================================================================== --- polly/lib/Analysis/ScopGraphPrinter.cpp +++ polly/lib/Analysis/ScopGraphPrinter.cpp @@ -13,12 +13,9 @@ // //===----------------------------------------------------------------------===// +#include "polly/ScopGraphPrinter.h" #include "polly/LinkAllPasses.h" #include "polly/ScopDetection.h" -#include "polly/Support/ScopLocation.h" -#include "llvm/Analysis/DOTGraphTraitsPass.h" -#include "llvm/Analysis/RegionInfo.h" -#include "llvm/Analysis/RegionIterator.h" #include "llvm/Support/CommandLine.h" using namespace polly; @@ -33,234 +30,131 @@ cl::Hidden, cl::init(false), cl::ZeroOrMore); namespace llvm { -template <> -struct GraphTraits : public GraphTraits { - static NodeRef getEntryNode(ScopDetection *SD) { - return GraphTraits::getEntryNode(SD->getRI()); - } - static nodes_iterator nodes_begin(ScopDetection *SD) { - return nodes_iterator::begin(getEntryNode(SD)); - } - static nodes_iterator nodes_end(ScopDetection *SD) { - return nodes_iterator::end(getEntryNode(SD)); - } -}; -template <> -struct GraphTraits - : public GraphTraits { - static NodeRef getEntryNode(ScopDetectionWrapperPass *P) { - return GraphTraits::getEntryNode(&P->getSD()); - } - static nodes_iterator nodes_begin(ScopDetectionWrapperPass *P) { - return nodes_iterator::begin(getEntryNode(P)); - } - static nodes_iterator nodes_end(ScopDetectionWrapperPass *P) { - return nodes_iterator::end(getEntryNode(P)); - } -}; +std::string DOTGraphTraits::getNodeLabel(RegionNode *Node, + RegionNode *Graph) { + if (!Node->isSubRegion()) { + BasicBlock *BB = Node->getNodeAs(); -template <> struct DOTGraphTraits : public DefaultDOTGraphTraits { - DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} + if (isSimple()) + return DOTGraphTraits::getSimpleNodeLabel(BB, nullptr); - std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) { - if (!Node->isSubRegion()) { - BasicBlock *BB = Node->getNodeAs(); + else + return DOTGraphTraits::getCompleteNodeLabel(BB, nullptr); + } - if (isSimple()) - return DOTGraphTraits::getSimpleNodeLabel(BB, nullptr); + return "Not implemented"; +} - else - return DOTGraphTraits::getCompleteNodeLabel(BB, nullptr); - } +std::string DOTGraphTraits::getEdgeAttributes( + RegionNode *srcNode, GraphTraits::ChildIteratorType CI, + ScopDetection *SD) { + RegionNode *destNode = *CI; - return "Not implemented"; - } -}; - -template <> -struct DOTGraphTraits - : public DOTGraphTraits { - DOTGraphTraits(bool isSimple = false) - : DOTGraphTraits(isSimple) {} - static std::string getGraphName(ScopDetectionWrapperPass *SD) { - return "Scop Graph"; - } + if (srcNode->isSubRegion() || destNode->isSubRegion()) + return ""; - std::string getEdgeAttributes(RegionNode *srcNode, - GraphTraits::ChildIteratorType CI, - ScopDetectionWrapperPass *P) { - RegionNode *destNode = *CI; - auto *SD = &P->getSD(); + // In case of a backedge, do not use it to define the layout of the nodes. + BasicBlock *srcBB = srcNode->getNodeAs(); + BasicBlock *destBB = destNode->getNodeAs(); - if (srcNode->isSubRegion() || destNode->isSubRegion()) - return ""; + RegionInfo *RI = SD->getRI(); + Region *R = RI->getRegionFor(destBB); - // In case of a backedge, do not use it to define the layout of the nodes. - BasicBlock *srcBB = srcNode->getNodeAs(); - BasicBlock *destBB = destNode->getNodeAs(); + while (R && R->getParent()) + if (R->getParent()->getEntry() == destBB) + R = R->getParent(); + else + break; - RegionInfo *RI = SD->getRI(); - Region *R = RI->getRegionFor(destBB); + if (R && R->getEntry() == destBB && R->contains(srcBB)) + return "constraint=false"; - while (R && R->getParent()) - if (R->getParent()->getEntry() == destBB) - R = R->getParent(); - else - break; + return ""; +} - if (R && R->getEntry() == destBB && R->contains(srcBB)) - return "constraint=false"; +std::string DOTGraphTraits::escapeString(std::string String) { + std::string Escaped; - return ""; - } + for (const auto &C : String) { + if (C == '"') + Escaped += '\\'; - std::string getNodeLabel(RegionNode *Node, ScopDetectionWrapperPass *P) { - return DOTGraphTraits::getNodeLabel( - Node, reinterpret_cast( - P->getSD().getRI()->getTopLevelRegion())); + Escaped += C; + } + return Escaped; +} + +void DOTGraphTraits::printRegionCluster(ScopDetection *SD, + const Region *R, + raw_ostream &O, + unsigned depth = 0) { + O.indent(2 * depth) << "subgraph cluster_" << static_cast(R) + << " {\n"; + unsigned LineBegin, LineEnd; + std::string FileName; + + getDebugLocation(R, LineBegin, LineEnd, FileName); + + std::string Location; + if (LineBegin != (unsigned)-1) { + Location = escapeString(FileName + ":" + std::to_string(LineBegin) + "-" + + std::to_string(LineEnd) + "\n"); } - static std::string escapeString(std::string String) { - std::string Escaped; - - for (const auto &C : String) { - if (C == '"') - Escaped += '\\'; + std::string ErrorMessage = SD->regionIsInvalidBecause(R); + ErrorMessage = escapeString(ErrorMessage); + O.indent(2 * (depth + 1)) + << "label = \"" << Location << ErrorMessage << "\";\n"; - Escaped += C; - } - return Escaped; - } + if (SD->isMaxRegionInScop(*R)) { + O.indent(2 * (depth + 1)) << "style = filled;\n"; - // Print the cluster of the subregions. This groups the single basic blocks - // and adds a different background color for each group. - static void printRegionCluster(ScopDetection *SD, const Region *R, - raw_ostream &O, unsigned depth = 0) { - O.indent(2 * depth) << "subgraph cluster_" << static_cast(R) - << " {\n"; - unsigned LineBegin, LineEnd; - std::string FileName; + // Set color to green. + O.indent(2 * (depth + 1)) << "color = 3"; + } else { + O.indent(2 * (depth + 1)) << "style = solid;\n"; - getDebugLocation(R, LineBegin, LineEnd, FileName); + int color = (R->getDepth() * 2 % 12) + 1; - std::string Location; - if (LineBegin != (unsigned)-1) { - Location = escapeString(FileName + ":" + std::to_string(LineBegin) + "-" + - std::to_string(LineEnd) + "\n"); - } + // We do not want green again. + if (color == 3) + color = 6; - std::string ErrorMessage = SD->regionIsInvalidBecause(R); - ErrorMessage = escapeString(ErrorMessage); - O.indent(2 * (depth + 1)) - << "label = \"" << Location << ErrorMessage << "\";\n"; + O.indent(2 * (depth + 1)) << "color = " << color << "\n"; + } - if (SD->isMaxRegionInScop(*R)) { - O.indent(2 * (depth + 1)) << "style = filled;\n"; + for (const auto &SubRegion : *R) + printRegionCluster(SD, SubRegion.get(), O, depth + 1); - // Set color to green. - O.indent(2 * (depth + 1)) << "color = 3"; - } else { - O.indent(2 * (depth + 1)) << "style = solid;\n"; + RegionInfo *RI = R->getRegionInfo(); - int color = (R->getDepth() * 2 % 12) + 1; + for (BasicBlock *BB : R->blocks()) + if (RI->getRegionFor(BB) == R) + O.indent(2 * (depth + 1)) + << "Node" + << static_cast(RI->getTopLevelRegion()->getBBNode(BB)) + << ";\n"; - // We do not want green again. - if (color == 3) - color = 6; + O.indent(2 * depth) << "}\n"; +} - O.indent(2 * (depth + 1)) << "color = " << color << "\n"; - } +void DOTGraphTraits::addCustomGraphFeatures( + ScopDetection *SD, GraphWriter &GW) { + raw_ostream &O = GW.getOStream(); + O << "\tcolorscheme = \"paired12\"\n"; + printRegionCluster(SD, SD->getRI()->getTopLevelRegion(), O, 4); +} - for (const auto &SubRegion : *R) - printRegionCluster(SD, SubRegion.get(), O, depth + 1); +} // namespace llvm - RegionInfo *RI = R->getRegionInfo(); +bool ScopViewer::processFunction(Function &F, const ScopDetection &SD) { + if (ViewFilter != "" && !F.getName().count(ViewFilter)) + return false; - for (BasicBlock *BB : R->blocks()) - if (RI->getRegionFor(BB) == R) - O.indent(2 * (depth + 1)) - << "Node" - << static_cast(RI->getTopLevelRegion()->getBBNode(BB)) - << ";\n"; + if (ViewAll) + return true; - O.indent(2 * depth) << "}\n"; - } - static void - addCustomGraphFeatures(const ScopDetectionWrapperPass *SD, - GraphWriter &GW) { - raw_ostream &O = GW.getOStream(); - O << "\tcolorscheme = \"paired12\"\n"; - printRegionCluster(&SD->getSD(), SD->getSD().getRI()->getTopLevelRegion(), - O, 4); - } -}; -} // end namespace llvm - -struct ScopViewer - : public LegacyDOTGraphTraitsViewer { - static char ID; - ScopViewer() - : LegacyDOTGraphTraitsViewer("scops", - ID) {} - bool processFunction(Function &F, ScopDetectionWrapperPass &SD) override { - if (ViewFilter != "" && !F.getName().count(ViewFilter)) - return false; - - if (ViewAll) - return true; - - // Check that at least one scop was detected. - return std::distance(SD.getSD().begin(), SD.getSD().end()) > 0; - } -}; -char ScopViewer::ID = 0; - -struct ScopOnlyViewer - : public LegacyDOTGraphTraitsViewer { - static char ID; - ScopOnlyViewer() - : LegacyDOTGraphTraitsViewer("scopsonly", - ID) {} -}; -char ScopOnlyViewer::ID = 0; - -struct ScopPrinter - : public LegacyDOTGraphTraitsPrinter { - static char ID; - ScopPrinter() - : LegacyDOTGraphTraitsPrinter("scops", - ID) {} -}; -char ScopPrinter::ID = 0; - -struct ScopOnlyPrinter - : public LegacyDOTGraphTraitsPrinter { - static char ID; - ScopOnlyPrinter() - : LegacyDOTGraphTraitsPrinter("scopsonly", - ID) {} -}; -char ScopOnlyPrinter::ID = 0; - -static RegisterPass X("view-scops", - "Polly - View Scops of function"); - -static RegisterPass - Y("view-scops-only", - "Polly - View Scops of function (with no function bodies)"); - -static RegisterPass M("dot-scops", - "Polly - Print Scops of function"); - -static RegisterPass - N("dot-scops-only", - "Polly - Print Scops of function (with no function bodies)"); - -Pass *polly::createDOTViewerPass() { return new ScopViewer(); } - -Pass *polly::createDOTOnlyViewerPass() { return new ScopOnlyViewer(); } - -Pass *polly::createDOTPrinterPass() { return new ScopPrinter(); } - -Pass *polly::createDOTOnlyPrinterPass() { return new ScopOnlyPrinter(); } + // Check that at least one scop was detected. + return std::distance(SD.begin(), SD.end()) > 0; +} Index: polly/lib/Support/PollyPasses.def =================================================================== --- polly/lib/Support/PollyPasses.def +++ polly/lib/Support/PollyPasses.def @@ -11,6 +11,10 @@ FUNCTION_PASS("polly-prepare", CodePreparationPass()) FUNCTION_PASS("print", ScopAnalysisPrinterPass(llvm::errs())) FUNCTION_PASS("print", ScopInfoPrinterPass(llvm::errs())) +FUNCTION_PASS("polly-scop-viewer", ScopViewer()) +FUNCTION_PASS("polly-scop-only-viewer", ScopOnlyViewer()) +FUNCTION_PASS("polly-scop-printer", ScopPrinter()) +FUNCTION_PASS("polly-scop-only-printer", ScopOnlyPrinter()) #undef FUNCTION_PASS #ifndef SCOP_ANALYSIS Index: polly/lib/Support/RegisterPasses.cpp =================================================================== --- polly/lib/Support/RegisterPasses.cpp +++ polly/lib/Support/RegisterPasses.cpp @@ -34,6 +34,7 @@ #include "polly/PruneUnprofitable.h" #include "polly/ScheduleOptimizer.h" #include "polly/ScopDetection.h" +#include "polly/ScopGraphPrinter.h" #include "polly/ScopInfo.h" #include "polly/Simplify.h" #include "polly/Support/DumpFunctionPass.h" @@ -330,15 +331,6 @@ if (PollyDetectOnly) return; - if (PollyViewer) - PM.add(polly::createDOTViewerPass()); - if (PollyOnlyViewer) - PM.add(polly::createDOTOnlyViewerPass()); - if (PollyPrinter) - PM.add(polly::createDOTPrinterPass()); - if (PollyOnlyPrinter) - PM.add(polly::createDOTOnlyPrinterPass()); - PM.add(polly::createScopInfoRegionPassPass()); if (EnablePolyhedralInfo) PM.add(polly::createPolyhedralInfoPass()); @@ -509,16 +501,13 @@ } if (PollyViewer) - llvm::report_fatal_error("Option -polly-show not supported with NPM", - false); + PM.addPass(ScopViewer()); if (PollyOnlyViewer) - llvm::report_fatal_error("Option -polly-show-only not supported with NPM", - false); + PM.addPass(ScopOnlyViewer()); if (PollyPrinter) - llvm::report_fatal_error("Option -polly-dot not supported with NPM", false); + PM.addPass(ScopPrinter()); if (PollyOnlyPrinter) - llvm::report_fatal_error("Option -polly-dot-only not supported with NPM", - false); + PM.addPass(ScopOnlyPrinter()); if (EnablePolyhedralInfo) llvm::report_fatal_error( "Option -polly-enable-polyhedralinfo not supported with NPM", false); Index: polly/test/ScopDetect/dot-scops.ll =================================================================== --- polly/test/ScopDetect/dot-scops.ll +++ polly/test/ScopDetect/dot-scops.ll @@ -1,4 +1,4 @@ -; RUN: opt %loadPolly -polly-scops -dot-scops -disable-output < %s +; RUN: opt %loadPolly "-passes=polly-scop-viewer" -disable-output < %s ; ; Check that the ScopPrinter does not crash. ; ScopPrinter needs the ScopDetection pass, which should depend on