1 //===- Standard pass instrumentations handling ----------------*- C++ -*--===// 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 /// \file 9 /// 10 /// This file defines IR-printing pass instrumentation callbacks as well as 11 /// StandardInstrumentations class that manages standard pass instrumentations. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/Passes/StandardInstrumentations.h" 16 #include "llvm/ADT/Any.h" 17 #include "llvm/ADT/Optional.h" 18 #include "llvm/Analysis/CallGraphSCCPass.h" 19 #include "llvm/Analysis/LazyCallGraph.h" 20 #include "llvm/Analysis/LoopInfo.h" 21 #include "llvm/IR/Function.h" 22 #include "llvm/IR/IRPrintingPasses.h" 23 #include "llvm/IR/Module.h" 24 #include "llvm/IR/PassInstrumentation.h" 25 #include "llvm/Support/CommandLine.h" 26 #include "llvm/Support/Debug.h" 27 #include "llvm/Support/FormatVariadic.h" 28 #include "llvm/Support/raw_ostream.h" 29 #include <vector> 30 31 using namespace llvm; 32 33 // TODO: remove once all required passes are marked as such. 34 static cl::opt<bool> 35 EnableOptnone("enable-npm-optnone", cl::init(false), 36 cl::desc("Enable skipping optional passes optnone functions " 37 "under new pass manager")); 38 39 // FIXME: Change `-debug-pass-manager` from boolean to enum type. Similar to 40 // `-debug-pass` in legacy PM. 41 static cl::opt<bool> 42 DebugPMVerbose("debug-pass-manager-verbose", cl::Hidden, cl::init(false), 43 cl::desc("Print all pass management debugging information. " 44 "`-debug-pass-manager` must also be specified")); 45 46 namespace { 47 48 /// Extracting Module out of \p IR unit. Also fills a textual description 49 /// of \p IR for use in header when printing. 50 Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) { 51 if (any_isa<const Module *>(IR)) 52 return std::make_pair(any_cast<const Module *>(IR), std::string()); 53 54 if (any_isa<const Function *>(IR)) { 55 const Function *F = any_cast<const Function *>(IR); 56 if (!llvm::isFunctionInPrintList(F->getName())) 57 return None; 58 const Module *M = F->getParent(); 59 return std::make_pair(M, formatv(" (function: {0})", F->getName()).str()); 60 } 61 62 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 63 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 64 for (const LazyCallGraph::Node &N : *C) { 65 const Function &F = N.getFunction(); 66 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 67 const Module *M = F.getParent(); 68 return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str()); 69 } 70 } 71 return None; 72 } 73 74 if (any_isa<const Loop *>(IR)) { 75 const Loop *L = any_cast<const Loop *>(IR); 76 const Function *F = L->getHeader()->getParent(); 77 if (!isFunctionInPrintList(F->getName())) 78 return None; 79 const Module *M = F->getParent(); 80 std::string LoopName; 81 raw_string_ostream ss(LoopName); 82 L->getHeader()->printAsOperand(ss, false); 83 return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str()); 84 } 85 86 llvm_unreachable("Unknown IR unit"); 87 } 88 89 void printIR(raw_ostream &OS, const Function *F, StringRef Banner, 90 StringRef Extra = StringRef(), bool Brief = false) { 91 if (Brief) { 92 OS << F->getName() << '\n'; 93 return; 94 } 95 96 if (!llvm::isFunctionInPrintList(F->getName())) 97 return; 98 OS << Banner << Extra << "\n" << static_cast<const Value &>(*F); 99 } 100 101 void printIR(raw_ostream &OS, const Module *M, StringRef Banner, 102 StringRef Extra = StringRef(), bool Brief = false) { 103 if (Brief) { 104 OS << M->getName() << '\n'; 105 return; 106 } 107 108 if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) { 109 OS << Banner << Extra << "\n"; 110 M->print(OS, nullptr, false); 111 } else { 112 for (const auto &F : M->functions()) { 113 printIR(OS, &F, Banner, Extra); 114 } 115 } 116 } 117 118 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C, StringRef Banner, 119 StringRef Extra = StringRef(), bool Brief = false) { 120 if (Brief) { 121 OS << *C << '\n'; 122 return; 123 } 124 125 bool BannerPrinted = false; 126 for (const LazyCallGraph::Node &N : *C) { 127 const Function &F = N.getFunction(); 128 if (!F.isDeclaration() && llvm::isFunctionInPrintList(F.getName())) { 129 if (!BannerPrinted) { 130 OS << Banner << Extra << "\n"; 131 BannerPrinted = true; 132 } 133 F.print(OS); 134 } 135 } 136 } 137 138 void printIR(raw_ostream &OS, const Loop *L, StringRef Banner, 139 bool Brief = false) { 140 if (Brief) { 141 OS << *L; 142 return; 143 } 144 145 const Function *F = L->getHeader()->getParent(); 146 if (!llvm::isFunctionInPrintList(F->getName())) 147 return; 148 llvm::printLoop(const_cast<Loop &>(*L), OS, std::string(Banner)); 149 } 150 151 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 152 /// llvm::Any and does actual print job. 153 void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner, 154 bool ForceModule = false, bool Brief = false) { 155 if (ForceModule) { 156 if (auto UnwrappedModule = unwrapModule(IR)) 157 printIR(OS, UnwrappedModule->first, Banner, UnwrappedModule->second); 158 return; 159 } 160 161 if (any_isa<const Module *>(IR)) { 162 const Module *M = any_cast<const Module *>(IR); 163 assert(M && "module should be valid for printing"); 164 printIR(OS, M, Banner, "", Brief); 165 return; 166 } 167 168 if (any_isa<const Function *>(IR)) { 169 const Function *F = any_cast<const Function *>(IR); 170 assert(F && "function should be valid for printing"); 171 printIR(OS, F, Banner, "", Brief); 172 return; 173 } 174 175 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 176 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 177 assert(C && "scc should be valid for printing"); 178 std::string Extra = std::string(formatv(" (scc: {0})", C->getName())); 179 printIR(OS, C, Banner, Extra, Brief); 180 return; 181 } 182 183 if (any_isa<const Loop *>(IR)) { 184 const Loop *L = any_cast<const Loop *>(IR); 185 assert(L && "Loop should be valid for printing"); 186 printIR(OS, L, Banner, Brief); 187 return; 188 } 189 llvm_unreachable("Unknown wrapped IR type"); 190 } 191 192 } // namespace 193 194 PrintIRInstrumentation::~PrintIRInstrumentation() { 195 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); 196 } 197 198 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { 199 assert(StoreModuleDesc); 200 const Module *M = nullptr; 201 std::string Extra; 202 if (auto UnwrappedModule = unwrapModule(IR)) 203 std::tie(M, Extra) = UnwrappedModule.getValue(); 204 ModuleDescStack.emplace_back(M, Extra, PassID); 205 } 206 207 PrintIRInstrumentation::PrintModuleDesc 208 PrintIRInstrumentation::popModuleDesc(StringRef PassID) { 209 assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); 210 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); 211 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); 212 return ModuleDesc; 213 } 214 215 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 216 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 217 return; 218 219 // Saving Module for AfterPassInvalidated operations. 220 // Note: here we rely on a fact that we do not change modules while 221 // traversing the pipeline, so the latest captured module is good 222 // for all print operations that has not happen yet. 223 if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID)) 224 pushModuleDesc(PassID, IR); 225 226 if (!llvm::shouldPrintBeforePass(PassID)) 227 return; 228 229 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); 230 unwrapAndPrint(dbgs(), IR, Banner, llvm::forcePrintModuleIR()); 231 return; 232 } 233 234 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 235 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 236 return; 237 238 if (!llvm::shouldPrintAfterPass(PassID)) 239 return; 240 241 if (StoreModuleDesc) 242 popModuleDesc(PassID); 243 244 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); 245 unwrapAndPrint(dbgs(), IR, Banner, llvm::forcePrintModuleIR()); 246 } 247 248 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 249 if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID)) 250 return; 251 252 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 253 return; 254 255 const Module *M; 256 std::string Extra; 257 StringRef StoredPassID; 258 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID); 259 // Additional filtering (e.g. -filter-print-func) can lead to module 260 // printing being skipped. 261 if (!M) 262 return; 263 264 SmallString<20> Banner = 265 formatv("*** IR Dump After {0} *** invalidated: ", PassID); 266 printIR(dbgs(), M, Banner, Extra); 267 } 268 269 void PrintIRInstrumentation::registerCallbacks( 270 PassInstrumentationCallbacks &PIC) { 271 // BeforePass callback is not just for printing, it also saves a Module 272 // for later use in AfterPassInvalidated. 273 StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass(); 274 if (llvm::shouldPrintBeforePass() || StoreModuleDesc) 275 PIC.registerBeforeNonSkippedPassCallback( 276 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 277 278 if (llvm::shouldPrintAfterPass()) { 279 PIC.registerAfterPassCallback( 280 [this](StringRef P, Any IR, const PreservedAnalyses &) { 281 this->printAfterPass(P, IR); 282 }); 283 PIC.registerAfterPassInvalidatedCallback( 284 [this](StringRef P, const PreservedAnalyses &) { 285 this->printAfterPassInvalidated(P); 286 }); 287 } 288 } 289 290 void OptNoneInstrumentation::registerCallbacks( 291 PassInstrumentationCallbacks &PIC) { 292 PIC.registerBeforePassCallback( 293 [this](StringRef P, Any IR) { return this->skip(P, IR); }); 294 } 295 296 bool OptNoneInstrumentation::skip(StringRef PassID, Any IR) { 297 if (!EnableOptnone) 298 return true; 299 const Function *F = nullptr; 300 if (any_isa<const Function *>(IR)) { 301 F = any_cast<const Function *>(IR); 302 } else if (any_isa<const Loop *>(IR)) { 303 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 304 } 305 return !(F && F->hasOptNone()); 306 } 307 308 void PrintPassInstrumentation::registerCallbacks( 309 PassInstrumentationCallbacks &PIC) { 310 if (!DebugLogging) 311 return; 312 313 std::vector<StringRef> SpecialPasses = {"PassManager"}; 314 if (!DebugPMVerbose) 315 SpecialPasses.emplace_back("PassAdaptor"); 316 317 PIC.registerBeforeSkippedPassCallback( 318 [SpecialPasses](StringRef PassID, Any IR) { 319 assert(!isSpecialPass(PassID, SpecialPasses) && 320 "Unexpectedly skipping special pass"); 321 322 dbgs() << "Skipping pass: " << PassID << " on "; 323 unwrapAndPrint(dbgs(), IR, "", false, true); 324 }); 325 326 PIC.registerBeforeNonSkippedPassCallback( 327 [SpecialPasses](StringRef PassID, Any IR) { 328 if (isSpecialPass(PassID, SpecialPasses)) 329 return; 330 331 dbgs() << "Running pass: " << PassID << " on "; 332 unwrapAndPrint(dbgs(), IR, "", false, true); 333 }); 334 335 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) { 336 dbgs() << "Running analysis: " << PassID << " on "; 337 unwrapAndPrint(dbgs(), IR, "", false, true); 338 }); 339 } 340 341 void StandardInstrumentations::registerCallbacks( 342 PassInstrumentationCallbacks &PIC) { 343 PrintIR.registerCallbacks(PIC); 344 PrintPass.registerCallbacks(PIC); 345 TimePasses.registerCallbacks(PIC); 346 OptNone.registerCallbacks(PIC); 347 } 348