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(const Function *F, StringRef Banner, StringRef Extra = StringRef(), 90 bool Brief = false) { 91 if (Brief) { 92 dbgs() << F->getName() << '\n'; 93 return; 94 } 95 96 if (!llvm::isFunctionInPrintList(F->getName())) 97 return; 98 dbgs() << Banner << Extra << "\n" << static_cast<const Value &>(*F); 99 } 100 101 void printIR(const Module *M, StringRef Banner, StringRef Extra = StringRef(), 102 bool Brief = false) { 103 if (Brief) { 104 dbgs() << M->getName() << '\n'; 105 return; 106 } 107 108 if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) { 109 dbgs() << Banner << Extra << "\n"; 110 M->print(dbgs(), nullptr, false); 111 } else { 112 for (const auto &F : M->functions()) { 113 printIR(&F, Banner, Extra); 114 } 115 } 116 } 117 118 void printIR(const LazyCallGraph::SCC *C, StringRef Banner, 119 StringRef Extra = StringRef(), bool Brief = false) { 120 if (Brief) { 121 dbgs() << *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 dbgs() << Banner << Extra << "\n"; 131 BannerPrinted = true; 132 } 133 F.print(dbgs()); 134 } 135 } 136 } 137 138 void printIR(const Loop *L, StringRef Banner, bool Brief = false) { 139 if (Brief) { 140 dbgs() << *L; 141 return; 142 } 143 144 const Function *F = L->getHeader()->getParent(); 145 if (!llvm::isFunctionInPrintList(F->getName())) 146 return; 147 llvm::printLoop(const_cast<Loop &>(*L), dbgs(), std::string(Banner)); 148 } 149 150 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 151 /// llvm::Any and does actual print job. 152 void unwrapAndPrint(Any IR, StringRef Banner, bool ForceModule = false, 153 bool Brief = false) { 154 if (ForceModule) { 155 if (auto UnwrappedModule = unwrapModule(IR)) 156 printIR(UnwrappedModule->first, Banner, UnwrappedModule->second); 157 return; 158 } 159 160 if (any_isa<const Module *>(IR)) { 161 const Module *M = any_cast<const Module *>(IR); 162 assert(M && "module should be valid for printing"); 163 printIR(M, Banner, "", Brief); 164 return; 165 } 166 167 if (any_isa<const Function *>(IR)) { 168 const Function *F = any_cast<const Function *>(IR); 169 assert(F && "function should be valid for printing"); 170 printIR(F, Banner, "", Brief); 171 return; 172 } 173 174 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 175 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 176 assert(C && "scc should be valid for printing"); 177 std::string Extra = std::string(formatv(" (scc: {0})", C->getName())); 178 printIR(C, Banner, Extra, Brief); 179 return; 180 } 181 182 if (any_isa<const Loop *>(IR)) { 183 const Loop *L = any_cast<const Loop *>(IR); 184 assert(L && "Loop should be valid for printing"); 185 printIR(L, Banner, Brief); 186 return; 187 } 188 llvm_unreachable("Unknown wrapped IR type"); 189 } 190 191 } // namespace 192 193 PrintIRInstrumentation::~PrintIRInstrumentation() { 194 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); 195 } 196 197 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { 198 assert(StoreModuleDesc); 199 const Module *M = nullptr; 200 std::string Extra; 201 if (auto UnwrappedModule = unwrapModule(IR)) 202 std::tie(M, Extra) = UnwrappedModule.getValue(); 203 ModuleDescStack.emplace_back(M, Extra, PassID); 204 } 205 206 PrintIRInstrumentation::PrintModuleDesc 207 PrintIRInstrumentation::popModuleDesc(StringRef PassID) { 208 assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); 209 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); 210 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); 211 return ModuleDesc; 212 } 213 214 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 215 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 216 return; 217 218 // Saving Module for AfterPassInvalidated operations. 219 // Note: here we rely on a fact that we do not change modules while 220 // traversing the pipeline, so the latest captured module is good 221 // for all print operations that has not happen yet. 222 if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID)) 223 pushModuleDesc(PassID, IR); 224 225 if (!llvm::shouldPrintBeforePass(PassID)) 226 return; 227 228 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); 229 unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); 230 return; 231 } 232 233 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 234 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 235 return; 236 237 if (!llvm::shouldPrintAfterPass(PassID)) 238 return; 239 240 if (StoreModuleDesc) 241 popModuleDesc(PassID); 242 243 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); 244 unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); 245 } 246 247 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 248 if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID)) 249 return; 250 251 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 252 return; 253 254 const Module *M; 255 std::string Extra; 256 StringRef StoredPassID; 257 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID); 258 // Additional filtering (e.g. -filter-print-func) can lead to module 259 // printing being skipped. 260 if (!M) 261 return; 262 263 SmallString<20> Banner = 264 formatv("*** IR Dump After {0} *** invalidated: ", PassID); 265 printIR(M, Banner, Extra); 266 } 267 268 void PrintIRInstrumentation::registerCallbacks( 269 PassInstrumentationCallbacks &PIC) { 270 // BeforePass callback is not just for printing, it also saves a Module 271 // for later use in AfterPassInvalidated. 272 StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass(); 273 if (llvm::shouldPrintBeforePass() || StoreModuleDesc) 274 PIC.registerBeforeNonSkippedPassCallback( 275 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 276 277 if (llvm::shouldPrintAfterPass()) { 278 PIC.registerAfterPassCallback( 279 [this](StringRef P, Any IR) { this->printAfterPass(P, IR); }); 280 PIC.registerAfterPassInvalidatedCallback( 281 [this](StringRef P) { this->printAfterPassInvalidated(P); }); 282 } 283 } 284 285 void OptNoneInstrumentation::registerCallbacks( 286 PassInstrumentationCallbacks &PIC) { 287 PIC.registerBeforePassCallback( 288 [this](StringRef P, Any IR) { return this->skip(P, IR); }); 289 } 290 291 bool OptNoneInstrumentation::skip(StringRef PassID, Any IR) { 292 if (!EnableOptnone) 293 return true; 294 const Function *F = nullptr; 295 if (any_isa<const Function *>(IR)) { 296 F = any_cast<const Function *>(IR); 297 } else if (any_isa<const Loop *>(IR)) { 298 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 299 } 300 if (F && F->hasOptNone()) { 301 if (DebugLogging) 302 dbgs() << "Skipping pass: " << PassID << " (optnone)\n"; 303 return false; 304 } 305 return true; 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.registerBeforeNonSkippedPassCallback( 318 [SpecialPasses](StringRef PassID, Any IR) { 319 if (isSpecialPass(PassID, SpecialPasses)) 320 return; 321 322 dbgs() << "Running pass: " << PassID << " on "; 323 unwrapAndPrint(IR, "", false, true); 324 }); 325 326 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) { 327 dbgs() << "Running analysis: " << PassID << " on "; 328 unwrapAndPrint(IR, "", false, true); 329 }); 330 } 331 332 void StandardInstrumentations::registerCallbacks( 333 PassInstrumentationCallbacks &PIC) { 334 PrintIR.registerCallbacks(PIC); 335 PrintPass.registerCallbacks(PIC); 336 TimePasses.registerCallbacks(PIC); 337 OptNone.registerCallbacks(PIC); 338 } 339