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 cl::opt<bool> PreservedCFGCheckerInstrumentation::VerifyPreservedCFG( 40 "verify-cfg-preserved", cl::Hidden, 41 #ifdef NDEBUG 42 cl::init(false)); 43 #else 44 cl::init(true)); 45 #endif 46 47 // FIXME: Change `-debug-pass-manager` from boolean to enum type. Similar to 48 // `-debug-pass` in legacy PM. 49 static cl::opt<bool> 50 DebugPMVerbose("debug-pass-manager-verbose", cl::Hidden, cl::init(false), 51 cl::desc("Print all pass management debugging information. " 52 "`-debug-pass-manager` must also be specified")); 53 54 namespace { 55 56 /// Extracting Module out of \p IR unit. Also fills a textual description 57 /// of \p IR for use in header when printing. 58 Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) { 59 if (any_isa<const Module *>(IR)) 60 return std::make_pair(any_cast<const Module *>(IR), std::string()); 61 62 if (any_isa<const Function *>(IR)) { 63 const Function *F = any_cast<const Function *>(IR); 64 if (!llvm::isFunctionInPrintList(F->getName())) 65 return None; 66 const Module *M = F->getParent(); 67 return std::make_pair(M, formatv(" (function: {0})", F->getName()).str()); 68 } 69 70 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 71 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 72 for (const LazyCallGraph::Node &N : *C) { 73 const Function &F = N.getFunction(); 74 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 75 const Module *M = F.getParent(); 76 return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str()); 77 } 78 } 79 return None; 80 } 81 82 if (any_isa<const Loop *>(IR)) { 83 const Loop *L = any_cast<const Loop *>(IR); 84 const Function *F = L->getHeader()->getParent(); 85 if (!isFunctionInPrintList(F->getName())) 86 return None; 87 const Module *M = F->getParent(); 88 std::string LoopName; 89 raw_string_ostream ss(LoopName); 90 L->getHeader()->printAsOperand(ss, false); 91 return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str()); 92 } 93 94 llvm_unreachable("Unknown IR unit"); 95 } 96 97 void printIR(raw_ostream &OS, const Function *F, StringRef Banner, 98 StringRef Extra = StringRef(), bool Brief = false) { 99 if (Brief) { 100 OS << F->getName() << '\n'; 101 return; 102 } 103 104 if (!llvm::isFunctionInPrintList(F->getName())) 105 return; 106 OS << Banner << Extra << "\n" << static_cast<const Value &>(*F); 107 } 108 109 void printIR(raw_ostream &OS, const Module *M, StringRef Banner, 110 StringRef Extra = StringRef(), bool Brief = false) { 111 if (Brief) { 112 OS << M->getName() << '\n'; 113 return; 114 } 115 116 if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) { 117 OS << Banner << Extra << "\n"; 118 M->print(OS, nullptr, false); 119 } else { 120 for (const auto &F : M->functions()) { 121 printIR(OS, &F, Banner, Extra); 122 } 123 } 124 } 125 126 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C, StringRef Banner, 127 StringRef Extra = StringRef(), bool Brief = false) { 128 if (Brief) { 129 OS << *C << '\n'; 130 return; 131 } 132 133 bool BannerPrinted = false; 134 for (const LazyCallGraph::Node &N : *C) { 135 const Function &F = N.getFunction(); 136 if (!F.isDeclaration() && llvm::isFunctionInPrintList(F.getName())) { 137 if (!BannerPrinted) { 138 OS << Banner << Extra << "\n"; 139 BannerPrinted = true; 140 } 141 F.print(OS); 142 } 143 } 144 } 145 146 void printIR(raw_ostream &OS, const Loop *L, StringRef Banner, 147 bool Brief = false) { 148 if (Brief) { 149 OS << *L; 150 return; 151 } 152 153 const Function *F = L->getHeader()->getParent(); 154 if (!llvm::isFunctionInPrintList(F->getName())) 155 return; 156 llvm::printLoop(const_cast<Loop &>(*L), OS, std::string(Banner)); 157 } 158 159 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 160 /// llvm::Any and does actual print job. 161 void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner, 162 bool ForceModule = false, bool Brief = false) { 163 if (ForceModule) { 164 if (auto UnwrappedModule = unwrapModule(IR)) 165 printIR(OS, UnwrappedModule->first, Banner, UnwrappedModule->second); 166 return; 167 } 168 169 if (any_isa<const Module *>(IR)) { 170 const Module *M = any_cast<const Module *>(IR); 171 assert(M && "module should be valid for printing"); 172 printIR(OS, M, Banner, "", Brief); 173 return; 174 } 175 176 if (any_isa<const Function *>(IR)) { 177 const Function *F = any_cast<const Function *>(IR); 178 assert(F && "function should be valid for printing"); 179 printIR(OS, F, Banner, "", Brief); 180 return; 181 } 182 183 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 184 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 185 assert(C && "scc should be valid for printing"); 186 std::string Extra = std::string(formatv(" (scc: {0})", C->getName())); 187 printIR(OS, C, Banner, Extra, Brief); 188 return; 189 } 190 191 if (any_isa<const Loop *>(IR)) { 192 const Loop *L = any_cast<const Loop *>(IR); 193 assert(L && "Loop should be valid for printing"); 194 printIR(OS, L, Banner, Brief); 195 return; 196 } 197 llvm_unreachable("Unknown wrapped IR type"); 198 } 199 200 } // namespace 201 202 PrintIRInstrumentation::~PrintIRInstrumentation() { 203 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); 204 } 205 206 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { 207 assert(StoreModuleDesc); 208 const Module *M = nullptr; 209 std::string Extra; 210 if (auto UnwrappedModule = unwrapModule(IR)) 211 std::tie(M, Extra) = UnwrappedModule.getValue(); 212 ModuleDescStack.emplace_back(M, Extra, PassID); 213 } 214 215 PrintIRInstrumentation::PrintModuleDesc 216 PrintIRInstrumentation::popModuleDesc(StringRef PassID) { 217 assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); 218 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); 219 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); 220 return ModuleDesc; 221 } 222 223 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 224 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 225 return; 226 227 // Saving Module for AfterPassInvalidated operations. 228 // Note: here we rely on a fact that we do not change modules while 229 // traversing the pipeline, so the latest captured module is good 230 // for all print operations that has not happen yet. 231 if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID)) 232 pushModuleDesc(PassID, IR); 233 234 if (!llvm::shouldPrintBeforePass(PassID)) 235 return; 236 237 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); 238 unwrapAndPrint(dbgs(), IR, Banner, llvm::forcePrintModuleIR()); 239 return; 240 } 241 242 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 243 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 244 return; 245 246 if (!llvm::shouldPrintAfterPass(PassID)) 247 return; 248 249 if (StoreModuleDesc) 250 popModuleDesc(PassID); 251 252 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); 253 unwrapAndPrint(dbgs(), IR, Banner, llvm::forcePrintModuleIR()); 254 } 255 256 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 257 if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID)) 258 return; 259 260 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<")) 261 return; 262 263 const Module *M; 264 std::string Extra; 265 StringRef StoredPassID; 266 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID); 267 // Additional filtering (e.g. -filter-print-func) can lead to module 268 // printing being skipped. 269 if (!M) 270 return; 271 272 SmallString<20> Banner = 273 formatv("*** IR Dump After {0} *** invalidated: ", PassID); 274 printIR(dbgs(), M, Banner, Extra); 275 } 276 277 void PrintIRInstrumentation::registerCallbacks( 278 PassInstrumentationCallbacks &PIC) { 279 // BeforePass callback is not just for printing, it also saves a Module 280 // for later use in AfterPassInvalidated. 281 StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass(); 282 if (llvm::shouldPrintBeforePass() || StoreModuleDesc) 283 PIC.registerBeforeNonSkippedPassCallback( 284 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 285 286 if (llvm::shouldPrintAfterPass()) { 287 PIC.registerAfterPassCallback( 288 [this](StringRef P, Any IR, const PreservedAnalyses &) { 289 this->printAfterPass(P, IR); 290 }); 291 PIC.registerAfterPassInvalidatedCallback( 292 [this](StringRef P, const PreservedAnalyses &) { 293 this->printAfterPassInvalidated(P); 294 }); 295 } 296 } 297 298 void OptNoneInstrumentation::registerCallbacks( 299 PassInstrumentationCallbacks &PIC) { 300 PIC.registerBeforePassCallback( 301 [this](StringRef P, Any IR) { return this->skip(P, IR); }); 302 } 303 304 bool OptNoneInstrumentation::skip(StringRef PassID, Any IR) { 305 if (!EnableOptnone) 306 return true; 307 const Function *F = nullptr; 308 if (any_isa<const Function *>(IR)) { 309 F = any_cast<const Function *>(IR); 310 } else if (any_isa<const Loop *>(IR)) { 311 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 312 } 313 return !(F && F->hasOptNone()); 314 } 315 316 void PrintPassInstrumentation::registerCallbacks( 317 PassInstrumentationCallbacks &PIC) { 318 if (!DebugLogging) 319 return; 320 321 std::vector<StringRef> SpecialPasses = {"PassManager"}; 322 if (!DebugPMVerbose) 323 SpecialPasses.emplace_back("PassAdaptor"); 324 325 PIC.registerBeforeSkippedPassCallback( 326 [SpecialPasses](StringRef PassID, Any IR) { 327 assert(!isSpecialPass(PassID, SpecialPasses) && 328 "Unexpectedly skipping special pass"); 329 330 dbgs() << "Skipping pass: " << PassID << " on "; 331 unwrapAndPrint(dbgs(), IR, "", false, true); 332 }); 333 334 PIC.registerBeforeNonSkippedPassCallback( 335 [SpecialPasses](StringRef PassID, Any IR) { 336 if (isSpecialPass(PassID, SpecialPasses)) 337 return; 338 339 dbgs() << "Running pass: " << PassID << " on "; 340 unwrapAndPrint(dbgs(), IR, "", false, true); 341 }); 342 343 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) { 344 dbgs() << "Running analysis: " << PassID << " on "; 345 unwrapAndPrint(dbgs(), IR, "", false, true); 346 }); 347 } 348 349 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F, 350 bool TrackBBLifetime) { 351 if (TrackBBLifetime) 352 BBGuards = DenseMap<intptr_t, BBGuard>(F->size()); 353 for (const auto &BB : *F) { 354 if (BBGuards) 355 BBGuards->try_emplace(intptr_t(&BB), &BB); 356 for (auto *Succ : successors(&BB)) { 357 Graph[&BB][Succ]++; 358 if (BBGuards) 359 BBGuards->try_emplace(intptr_t(Succ), Succ); 360 } 361 } 362 } 363 364 static void printBBName(raw_ostream &out, const BasicBlock *BB) { 365 if (BB->hasName()) { 366 out << BB->getName() << "<" << BB << ">"; 367 return; 368 } 369 370 if (!BB->getParent()) { 371 out << "unnamed_removed<" << BB << ">"; 372 return; 373 } 374 375 if (BB == &BB->getParent()->getEntryBlock()) { 376 out << "entry" 377 << "<" << BB << ">"; 378 return; 379 } 380 381 unsigned FuncOrderBlockNum = 0; 382 for (auto &FuncBB : *BB->getParent()) { 383 if (&FuncBB == BB) 384 break; 385 FuncOrderBlockNum++; 386 } 387 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">"; 388 } 389 390 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out, 391 const CFG &Before, 392 const CFG &After) { 393 assert(!After.isPoisoned()); 394 395 // Print function name. 396 const CFG *FuncGraph = nullptr; 397 if (!After.Graph.empty()) 398 FuncGraph = &After; 399 else if (!Before.isPoisoned() && !Before.Graph.empty()) 400 FuncGraph = &Before; 401 402 if (FuncGraph) 403 out << "In function @" 404 << FuncGraph->Graph.begin()->first->getParent()->getName() << "\n"; 405 406 if (Before.isPoisoned()) { 407 out << "Some blocks were deleted\n"; 408 return; 409 } 410 411 // Find and print graph differences. 412 if (Before.Graph.size() != After.Graph.size()) 413 out << "Different number of non-leaf basic blocks: before=" 414 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n"; 415 416 for (auto &BB : Before.Graph) { 417 auto BA = After.Graph.find(BB.first); 418 if (BA == After.Graph.end()) { 419 out << "Non-leaf block "; 420 printBBName(out, BB.first); 421 out << " is removed (" << BB.second.size() << " successors)\n"; 422 } 423 } 424 425 for (auto &BA : After.Graph) { 426 auto BB = Before.Graph.find(BA.first); 427 if (BB == Before.Graph.end()) { 428 out << "Non-leaf block "; 429 printBBName(out, BA.first); 430 out << " is added (" << BA.second.size() << " successors)\n"; 431 continue; 432 } 433 434 if (BB->second == BA.second) 435 continue; 436 437 out << "Different successors of block "; 438 printBBName(out, BA.first); 439 out << " (unordered):\n"; 440 out << "- before (" << BB->second.size() << "): "; 441 for (auto &SuccB : BB->second) { 442 printBBName(out, SuccB.first); 443 if (SuccB.second != 1) 444 out << "(" << SuccB.second << "), "; 445 else 446 out << ", "; 447 } 448 out << "\n"; 449 out << "- after (" << BA.second.size() << "): "; 450 for (auto &SuccA : BA.second) { 451 printBBName(out, SuccA.first); 452 if (SuccA.second != 1) 453 out << "(" << SuccA.second << "), "; 454 else 455 out << ", "; 456 } 457 out << "\n"; 458 } 459 } 460 461 void PreservedCFGCheckerInstrumentation::registerCallbacks( 462 PassInstrumentationCallbacks &PIC) { 463 if (!VerifyPreservedCFG) 464 return; 465 466 PIC.registerBeforeNonSkippedPassCallback([this](StringRef P, Any IR) { 467 if (any_isa<const Function *>(IR)) 468 GraphStackBefore.emplace_back(P, CFG(any_cast<const Function *>(IR))); 469 else 470 GraphStackBefore.emplace_back(P, None); 471 }); 472 473 PIC.registerAfterPassInvalidatedCallback( 474 [this](StringRef P, const PreservedAnalyses &PassPA) { 475 auto Before = GraphStackBefore.pop_back_val(); 476 assert(Before.first == P && 477 "Before and After callbacks must correspond"); 478 (void)Before; 479 }); 480 481 PIC.registerAfterPassCallback([this](StringRef P, Any IR, 482 const PreservedAnalyses &PassPA) { 483 auto Before = GraphStackBefore.pop_back_val(); 484 assert(Before.first == P && "Before and After callbacks must correspond"); 485 auto &GraphBefore = Before.second; 486 487 if (!PassPA.allAnalysesInSetPreserved<CFGAnalyses>()) 488 return; 489 490 if (any_isa<const Function *>(IR)) { 491 assert(GraphBefore && "Must be built in BeforePassCallback"); 492 CFG GraphAfter(any_cast<const Function *>(IR), false /* NeedsGuard */); 493 if (GraphAfter == *GraphBefore) 494 return; 495 496 dbgs() << "Error: " << P 497 << " reported it preserved CFG, but changes detected:\n"; 498 CFG::printDiff(dbgs(), *GraphBefore, GraphAfter); 499 report_fatal_error(Twine("Preserved CFG changed by ", P)); 500 } 501 }); 502 } 503 504 void StandardInstrumentations::registerCallbacks( 505 PassInstrumentationCallbacks &PIC) { 506 PrintIR.registerCallbacks(PIC); 507 PrintPass.registerCallbacks(PIC); 508 TimePasses.registerCallbacks(PIC); 509 OptNone.registerCallbacks(PIC); 510 PreservedCFGChecker.registerCallbacks(PIC); 511 } 512