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 30 using namespace llvm; 31 32 // TODO: remove once all required passes are marked as such. 33 static cl::opt<bool> 34 EnableOptnone("enable-npm-optnone", cl::init(false), 35 cl::desc("Enable skipping optional passes optnone functions " 36 "under new pass manager")); 37 38 namespace { 39 40 /// Extracting Module out of \p IR unit. Also fills a textual description 41 /// of \p IR for use in header when printing. 42 Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) { 43 if (any_isa<const Module *>(IR)) 44 return std::make_pair(any_cast<const Module *>(IR), std::string()); 45 46 if (any_isa<const Function *>(IR)) { 47 const Function *F = any_cast<const Function *>(IR); 48 if (!llvm::isFunctionInPrintList(F->getName())) 49 return None; 50 const Module *M = F->getParent(); 51 return std::make_pair(M, formatv(" (function: {0})", F->getName()).str()); 52 } 53 54 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 55 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 56 for (const LazyCallGraph::Node &N : *C) { 57 const Function &F = N.getFunction(); 58 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 59 const Module *M = F.getParent(); 60 return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str()); 61 } 62 } 63 return None; 64 } 65 66 if (any_isa<const Loop *>(IR)) { 67 const Loop *L = any_cast<const Loop *>(IR); 68 const Function *F = L->getHeader()->getParent(); 69 if (!isFunctionInPrintList(F->getName())) 70 return None; 71 const Module *M = F->getParent(); 72 std::string LoopName; 73 raw_string_ostream ss(LoopName); 74 L->getHeader()->printAsOperand(ss, false); 75 return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str()); 76 } 77 78 llvm_unreachable("Unknown IR unit"); 79 } 80 81 void printIR(const Function *F, StringRef Banner, 82 StringRef Extra = StringRef()) { 83 if (!llvm::isFunctionInPrintList(F->getName())) 84 return; 85 dbgs() << Banner << Extra << "\n" << static_cast<const Value &>(*F); 86 } 87 88 void printIR(const Module *M, StringRef Banner, StringRef Extra = StringRef()) { 89 if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) { 90 dbgs() << Banner << Extra << "\n"; 91 M->print(dbgs(), nullptr, false); 92 } else { 93 for (const auto &F : M->functions()) { 94 printIR(&F, Banner, Extra); 95 } 96 } 97 } 98 99 void printIR(const LazyCallGraph::SCC *C, StringRef Banner, 100 StringRef Extra = StringRef()) { 101 bool BannerPrinted = false; 102 for (const LazyCallGraph::Node &N : *C) { 103 const Function &F = N.getFunction(); 104 if (!F.isDeclaration() && llvm::isFunctionInPrintList(F.getName())) { 105 if (!BannerPrinted) { 106 dbgs() << Banner << Extra << "\n"; 107 BannerPrinted = true; 108 } 109 F.print(dbgs()); 110 } 111 } 112 } 113 void printIR(const Loop *L, StringRef Banner) { 114 const Function *F = L->getHeader()->getParent(); 115 if (!llvm::isFunctionInPrintList(F->getName())) 116 return; 117 llvm::printLoop(const_cast<Loop &>(*L), dbgs(), std::string(Banner)); 118 } 119 120 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 121 /// llvm::Any and does actual print job. 122 void unwrapAndPrint(Any IR, StringRef Banner, bool ForceModule = false) { 123 if (ForceModule) { 124 if (auto UnwrappedModule = unwrapModule(IR)) 125 printIR(UnwrappedModule->first, Banner, UnwrappedModule->second); 126 return; 127 } 128 129 if (any_isa<const Module *>(IR)) { 130 const Module *M = any_cast<const Module *>(IR); 131 assert(M && "module should be valid for printing"); 132 printIR(M, Banner); 133 return; 134 } 135 136 if (any_isa<const Function *>(IR)) { 137 const Function *F = any_cast<const Function *>(IR); 138 assert(F && "function should be valid for printing"); 139 printIR(F, Banner); 140 return; 141 } 142 143 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 144 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 145 assert(C && "scc should be valid for printing"); 146 std::string Extra = std::string(formatv(" (scc: {0})", C->getName())); 147 printIR(C, Banner, Extra); 148 return; 149 } 150 151 if (any_isa<const Loop *>(IR)) { 152 const Loop *L = any_cast<const Loop *>(IR); 153 assert(L && "Loop should be valid for printing"); 154 printIR(L, Banner); 155 return; 156 } 157 llvm_unreachable("Unknown wrapped IR type"); 158 } 159 160 } // namespace 161 162 PrintIRInstrumentation::~PrintIRInstrumentation() { 163 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); 164 } 165 166 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { 167 assert(StoreModuleDesc); 168 const Module *M = nullptr; 169 std::string Extra; 170 if (auto UnwrappedModule = unwrapModule(IR)) 171 std::tie(M, Extra) = UnwrappedModule.getValue(); 172 ModuleDescStack.emplace_back(M, Extra, PassID); 173 } 174 175 PrintIRInstrumentation::PrintModuleDesc 176 PrintIRInstrumentation::popModuleDesc(StringRef PassID) { 177 assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); 178 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); 179 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); 180 return ModuleDesc; 181 } 182 183 bool PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 184 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 185 return true; 186 187 // Saving Module for AfterPassInvalidated operations. 188 // Note: here we rely on a fact that we do not change modules while 189 // traversing the pipeline, so the latest captured module is good 190 // for all print operations that has not happen yet. 191 if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID)) 192 pushModuleDesc(PassID, IR); 193 194 if (!llvm::shouldPrintBeforePass(PassID)) 195 return true; 196 197 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); 198 unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); 199 return true; 200 } 201 202 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 203 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 204 return; 205 206 if (!llvm::shouldPrintAfterPass(PassID)) 207 return; 208 209 if (StoreModuleDesc) 210 popModuleDesc(PassID); 211 212 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); 213 unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR()); 214 } 215 216 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 217 if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID)) 218 return; 219 220 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 221 return; 222 223 const Module *M; 224 std::string Extra; 225 StringRef StoredPassID; 226 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID); 227 // Additional filtering (e.g. -filter-print-func) can lead to module 228 // printing being skipped. 229 if (!M) 230 return; 231 232 SmallString<20> Banner = 233 formatv("*** IR Dump After {0} *** invalidated: ", PassID); 234 printIR(M, Banner, Extra); 235 } 236 237 void PrintIRInstrumentation::registerCallbacks( 238 PassInstrumentationCallbacks &PIC) { 239 // BeforePass callback is not just for printing, it also saves a Module 240 // for later use in AfterPassInvalidated. 241 StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass(); 242 if (llvm::shouldPrintBeforePass() || StoreModuleDesc) 243 PIC.registerBeforePassCallback( 244 [this](StringRef P, Any IR) { return this->printBeforePass(P, IR); }); 245 246 if (llvm::shouldPrintAfterPass()) { 247 PIC.registerAfterPassCallback( 248 [this](StringRef P, Any IR) { this->printAfterPass(P, IR); }); 249 PIC.registerAfterPassInvalidatedCallback( 250 [this](StringRef P) { this->printAfterPassInvalidated(P); }); 251 } 252 } 253 254 void OptNoneInstrumentation::registerCallbacks( 255 PassInstrumentationCallbacks &PIC) { 256 PIC.registerBeforePassCallback( 257 [this](StringRef P, Any IR) { return this->skip(P, IR); }); 258 } 259 260 bool OptNoneInstrumentation::skip(StringRef PassID, Any IR) { 261 if (!EnableOptnone) 262 return true; 263 const Function *F = nullptr; 264 if (any_isa<const Function *>(IR)) { 265 F = any_cast<const Function *>(IR); 266 } else if (any_isa<const Loop *>(IR)) { 267 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 268 } 269 if (F && F->hasOptNone()) { 270 if (DebugLogging) 271 dbgs() << "Skipping pass: " << PassID << " (optnone)\n"; 272 return false; 273 } 274 return true; 275 } 276 277 void StandardInstrumentations::registerCallbacks( 278 PassInstrumentationCallbacks &PIC) { 279 PrintIR.registerCallbacks(PIC); 280 TimePasses.registerCallbacks(PIC); 281 OptNone.registerCallbacks(PIC); 282 } 283