1 //===- GraphPrinter.cpp - Create a DOT output describing the Scop. --------===// 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 // Create a DOT output describing the Scop. 10 // 11 // For each function a dot file is created that shows the control flow graph of 12 // the function and highlights the detected Scops. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "polly/ScopGraphPrinter.h" 17 #include "polly/LinkAllPasses.h" 18 #include "polly/ScopDetection.h" 19 #include "llvm/Support/CommandLine.h" 20 21 using namespace polly; 22 using namespace llvm; 23 static cl::opt<std::string> 24 ViewFilter("polly-view-only", 25 cl::desc("Only view functions that match this pattern"), 26 cl::Hidden, cl::init("")); 27 28 static cl::opt<bool> ViewAll("polly-view-all", 29 cl::desc("Also show functions without any scops"), 30 cl::Hidden, cl::init(false)); 31 32 namespace llvm { 33 34 std::string DOTGraphTraits<ScopDetection *>::getEdgeAttributes( 35 RegionNode *srcNode, GraphTraits<RegionInfo *>::ChildIteratorType CI, 36 ScopDetection *SD) { 37 RegionNode *destNode = *CI; 38 39 if (srcNode->isSubRegion() || destNode->isSubRegion()) 40 return ""; 41 42 // In case of a backedge, do not use it to define the layout of the nodes. 43 BasicBlock *srcBB = srcNode->getNodeAs<BasicBlock>(); 44 BasicBlock *destBB = destNode->getNodeAs<BasicBlock>(); 45 46 RegionInfo *RI = SD->getRI(); 47 Region *R = RI->getRegionFor(destBB); 48 49 while (R && R->getParent()) 50 if (R->getParent()->getEntry() == destBB) 51 R = R->getParent(); 52 else 53 break; 54 55 if (R && R->getEntry() == destBB && R->contains(srcBB)) 56 return "constraint=false"; 57 58 return ""; 59 } 60 61 std::string 62 DOTGraphTraits<ScopDetection *>::escapeString(llvm::StringRef String) { 63 std::string Escaped; 64 65 for (const auto &C : String) { 66 if (C == '"') 67 Escaped += '\\'; 68 69 Escaped += C; 70 } 71 return Escaped; 72 } 73 74 void DOTGraphTraits<ScopDetection *>::printRegionCluster(ScopDetection *SD, 75 const Region *R, 76 raw_ostream &O, 77 unsigned depth) { 78 O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void *>(R) 79 << " {\n"; 80 unsigned LineBegin, LineEnd; 81 std::string FileName; 82 83 getDebugLocation(R, LineBegin, LineEnd, FileName); 84 85 std::string Location; 86 if (LineBegin != (unsigned)-1) { 87 Location = escapeString(FileName + ":" + std::to_string(LineBegin) + "-" + 88 std::to_string(LineEnd) + "\n"); 89 } 90 91 std::string ErrorMessage = SD->regionIsInvalidBecause(R); 92 ErrorMessage = escapeString(ErrorMessage); 93 O.indent(2 * (depth + 1)) 94 << "label = \"" << Location << ErrorMessage << "\";\n"; 95 96 if (SD->isMaxRegionInScop(*R)) { 97 O.indent(2 * (depth + 1)) << "style = filled;\n"; 98 99 // Set color to green. 100 O.indent(2 * (depth + 1)) << "color = 3"; 101 } else { 102 O.indent(2 * (depth + 1)) << "style = solid;\n"; 103 104 int color = (R->getDepth() * 2 % 12) + 1; 105 106 // We do not want green again. 107 if (color == 3) 108 color = 6; 109 110 O.indent(2 * (depth + 1)) << "color = " << color << "\n"; 111 } 112 113 for (const auto &SubRegion : *R) 114 printRegionCluster(SD, SubRegion.get(), O, depth + 1); 115 116 RegionInfo *RI = R->getRegionInfo(); 117 118 for (BasicBlock *BB : R->blocks()) 119 if (RI->getRegionFor(BB) == R) 120 O.indent(2 * (depth + 1)) 121 << "Node" 122 << static_cast<void *>(RI->getTopLevelRegion()->getBBNode(BB)) 123 << ";\n"; 124 125 O.indent(2 * depth) << "}\n"; 126 } 127 128 void DOTGraphTraits<ScopDetection *>::addCustomGraphFeatures( 129 ScopDetection *SD, GraphWriter<ScopDetection *> &GW) { 130 raw_ostream &O = GW.getOStream(); 131 O << "\tcolorscheme = \"paired12\"\n"; 132 printRegionCluster(SD, SD->getRI()->getTopLevelRegion(), O, 4); 133 } 134 135 } // namespace llvm 136 137 struct ScopDetectionAnalysisGraphTraits { 138 static ScopDetection *getGraph(ScopDetectionWrapperPass *Analysis) { 139 return &Analysis->getSD(); 140 } 141 }; 142 143 struct ScopViewerWrapperPass 144 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false, 145 ScopDetection *, 146 ScopDetectionAnalysisGraphTraits> { 147 static char ID; 148 ScopViewerWrapperPass() 149 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false, 150 ScopDetection *, 151 ScopDetectionAnalysisGraphTraits>( 152 "scops", ID) {} 153 bool processFunction(Function &F, ScopDetectionWrapperPass &SD) override { 154 if (ViewFilter != "" && !F.getName().count(ViewFilter)) 155 return false; 156 157 if (ViewAll) 158 return true; 159 160 // Check that at least one scop was detected. 161 return std::distance(SD.getSD().begin(), SD.getSD().end()) > 0; 162 } 163 }; 164 char ScopViewerWrapperPass::ID = 0; 165 166 struct ScopOnlyViewerWrapperPass 167 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false, 168 ScopDetection *, 169 ScopDetectionAnalysisGraphTraits> { 170 static char ID; 171 ScopOnlyViewerWrapperPass() 172 : DOTGraphTraitsViewerWrapperPass<ScopDetectionWrapperPass, false, 173 ScopDetection *, 174 ScopDetectionAnalysisGraphTraits>( 175 "scopsonly", ID) {} 176 }; 177 char ScopOnlyViewerWrapperPass::ID = 0; 178 179 struct ScopPrinterWrapperPass 180 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, false, 181 ScopDetection *, 182 ScopDetectionAnalysisGraphTraits> { 183 static char ID; 184 ScopPrinterWrapperPass() 185 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, false, 186 ScopDetection *, 187 ScopDetectionAnalysisGraphTraits>( 188 "scops", ID) {} 189 }; 190 char ScopPrinterWrapperPass::ID = 0; 191 192 struct ScopOnlyPrinterWrapperPass 193 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, true, 194 ScopDetection *, 195 ScopDetectionAnalysisGraphTraits> { 196 static char ID; 197 ScopOnlyPrinterWrapperPass() 198 : DOTGraphTraitsPrinterWrapperPass<ScopDetectionWrapperPass, true, 199 ScopDetection *, 200 ScopDetectionAnalysisGraphTraits>( 201 "scopsonly", ID) {} 202 }; 203 char ScopOnlyPrinterWrapperPass::ID = 0; 204 205 static RegisterPass<ScopViewerWrapperPass> X("view-scops", 206 "Polly - View Scops of function"); 207 208 static RegisterPass<ScopOnlyViewerWrapperPass> 209 Y("view-scops-only", 210 "Polly - View Scops of function (with no function bodies)"); 211 212 static RegisterPass<ScopPrinterWrapperPass> 213 M("dot-scops", "Polly - Print Scops of function"); 214 215 static RegisterPass<ScopOnlyPrinterWrapperPass> 216 N("dot-scops-only", 217 "Polly - Print Scops of function (with no function bodies)"); 218 219 Pass *polly::createDOTViewerWrapperPass() { 220 return new ScopViewerWrapperPass(); 221 } 222 223 Pass *polly::createDOTOnlyViewerWrapperPass() { 224 return new ScopOnlyViewerWrapperPass(); 225 } 226 227 Pass *polly::createDOTPrinterWrapperPass() { 228 return new ScopPrinterWrapperPass(); 229 } 230 231 Pass *polly::createDOTOnlyPrinterWrapperPass() { 232 return new ScopOnlyPrinterWrapperPass(); 233 } 234 235 bool ScopViewer::processFunction(Function &F, const ScopDetection &SD) { 236 if (ViewFilter != "" && !F.getName().count(ViewFilter)) 237 return false; 238 239 if (ViewAll) 240 return true; 241 242 // Check that at least one scop was detected. 243 return std::distance(SD.begin(), SD.end()) > 0; 244 } 245