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/ADT/StringRef.h" 19 #include "llvm/Analysis/CallGraphSCCPass.h" 20 #include "llvm/Analysis/LazyCallGraph.h" 21 #include "llvm/Analysis/LoopInfo.h" 22 #include "llvm/IR/Function.h" 23 #include "llvm/IR/Module.h" 24 #include "llvm/IR/PassInstrumentation.h" 25 #include "llvm/IR/PrintPasses.h" 26 #include "llvm/IR/Verifier.h" 27 #include "llvm/Support/CommandLine.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/FormatVariadic.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <unordered_set> 32 #include <vector> 33 34 using namespace llvm; 35 36 cl::opt<bool> PreservedCFGCheckerInstrumentation::VerifyPreservedCFG( 37 "verify-cfg-preserved", cl::Hidden, 38 #ifdef NDEBUG 39 cl::init(false)); 40 #else 41 cl::init(false)); 42 #endif 43 44 // FIXME: Change `-debug-pass-manager` from boolean to enum type. Similar to 45 // `-debug-pass` in legacy PM. 46 static cl::opt<bool> 47 DebugPMVerbose("debug-pass-manager-verbose", cl::Hidden, cl::init(false), 48 cl::desc("Print all pass management debugging information. " 49 "`-debug-pass-manager` must also be specified")); 50 51 // An option that prints out the IR after passes, similar to 52 // -print-after-all except that it only prints the IR after passes that 53 // change the IR. Those passes that do not make changes to the IR are 54 // reported as not making any changes. In addition, the initial IR is 55 // also reported. Other hidden options affect the output from this 56 // option. -filter-passes will limit the output to the named passes 57 // that actually change the IR and other passes are reported as filtered out. 58 // The specified passes will either be reported as making no changes (with 59 // no IR reported) or the changed IR will be reported. Also, the 60 // -filter-print-funcs and -print-module-scope options will do similar 61 // filtering based on function name, reporting changed IRs as functions(or 62 // modules if -print-module-scope is specified) for a particular function 63 // or indicating that the IR has been filtered out. The extra options 64 // can be combined, allowing only changed IRs for certain passes on certain 65 // functions to be reported in different formats, with the rest being 66 // reported as filtered out. The -print-before-changed option will print 67 // the IR as it was before each pass that changed it. 68 static cl::opt<bool> PrintChanged("print-changed", 69 cl::desc("Print changed IRs"), 70 cl::init(false), cl::Hidden); 71 // An option that supports the -print-changed option. See 72 // the description for -print-changed for an explanation of the use 73 // of this option. Note that this option has no effect without -print-changed. 74 static cl::list<std::string> 75 PrintPassesList("filter-passes", cl::value_desc("pass names"), 76 cl::desc("Only consider IR changes for passes whose names " 77 "match for the print-changed option"), 78 cl::CommaSeparated, cl::Hidden); 79 // An option that supports the -print-changed option. See 80 // the description for -print-changed for an explanation of the use 81 // of this option. Note that this option has no effect without -print-changed. 82 static cl::opt<bool> 83 PrintChangedBefore("print-before-changed", 84 cl::desc("Print before passes that change them"), 85 cl::init(false), cl::Hidden); 86 87 namespace { 88 89 /// Extracting Module out of \p IR unit. Also fills a textual description 90 /// of \p IR for use in header when printing. 91 Optional<std::pair<const Module *, std::string>> 92 unwrapModule(Any IR, bool Force = false) { 93 if (any_isa<const Module *>(IR)) 94 return std::make_pair(any_cast<const Module *>(IR), std::string()); 95 96 if (any_isa<const Function *>(IR)) { 97 const Function *F = any_cast<const Function *>(IR); 98 if (!Force && !isFunctionInPrintList(F->getName())) 99 return None; 100 101 const Module *M = F->getParent(); 102 return std::make_pair(M, formatv(" (function: {0})", F->getName()).str()); 103 } 104 105 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 106 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 107 for (const LazyCallGraph::Node &N : *C) { 108 const Function &F = N.getFunction(); 109 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) { 110 const Module *M = F.getParent(); 111 return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str()); 112 } 113 } 114 assert(!Force && "Expected to have made a pair when forced."); 115 return None; 116 } 117 118 if (any_isa<const Loop *>(IR)) { 119 const Loop *L = any_cast<const Loop *>(IR); 120 const Function *F = L->getHeader()->getParent(); 121 if (!Force && !isFunctionInPrintList(F->getName())) 122 return None; 123 const Module *M = F->getParent(); 124 std::string LoopName; 125 raw_string_ostream ss(LoopName); 126 L->getHeader()->printAsOperand(ss, false); 127 return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str()); 128 } 129 130 llvm_unreachable("Unknown IR unit"); 131 } 132 133 void printIR(raw_ostream &OS, const Function *F, StringRef Banner, 134 StringRef Extra = StringRef(), bool Brief = false) { 135 if (Brief) { 136 OS << F->getName() << '\n'; 137 return; 138 } 139 140 if (!isFunctionInPrintList(F->getName())) 141 return; 142 OS << Banner << Extra << "\n" << static_cast<const Value &>(*F); 143 } 144 145 void printIR(raw_ostream &OS, const Module *M, StringRef Banner, 146 StringRef Extra = StringRef(), bool Brief = false, 147 bool ShouldPreserveUseListOrder = false) { 148 if (Brief) { 149 OS << M->getName() << '\n'; 150 return; 151 } 152 153 if (isFunctionInPrintList("*") || forcePrintModuleIR()) { 154 OS << Banner << Extra << "\n"; 155 M->print(OS, nullptr, ShouldPreserveUseListOrder); 156 } else { 157 for (const auto &F : M->functions()) { 158 printIR(OS, &F, Banner, Extra); 159 } 160 } 161 } 162 163 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C, StringRef Banner, 164 StringRef Extra = StringRef(), bool Brief = false) { 165 if (Brief) { 166 OS << *C << '\n'; 167 return; 168 } 169 170 bool BannerPrinted = false; 171 for (const LazyCallGraph::Node &N : *C) { 172 const Function &F = N.getFunction(); 173 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 174 if (!BannerPrinted) { 175 OS << Banner << Extra << "\n"; 176 BannerPrinted = true; 177 } 178 F.print(OS); 179 } 180 } 181 } 182 183 void printIR(raw_ostream &OS, const Loop *L, StringRef Banner, 184 bool Brief = false) { 185 if (Brief) { 186 OS << *L; 187 return; 188 } 189 190 const Function *F = L->getHeader()->getParent(); 191 if (!isFunctionInPrintList(F->getName())) 192 return; 193 printLoop(const_cast<Loop &>(*L), OS, std::string(Banner)); 194 } 195 196 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 197 /// llvm::Any and does actual print job. 198 void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner, 199 bool ForceModule = false, bool Brief = false, 200 bool ShouldPreserveUseListOrder = false) { 201 if (ForceModule) { 202 if (auto UnwrappedModule = unwrapModule(IR)) 203 printIR(OS, UnwrappedModule->first, Banner, UnwrappedModule->second, 204 Brief, ShouldPreserveUseListOrder); 205 return; 206 } 207 208 if (any_isa<const Module *>(IR)) { 209 const Module *M = any_cast<const Module *>(IR); 210 assert(M && "module should be valid for printing"); 211 printIR(OS, M, Banner, "", Brief, ShouldPreserveUseListOrder); 212 return; 213 } 214 215 if (any_isa<const Function *>(IR)) { 216 const Function *F = any_cast<const Function *>(IR); 217 assert(F && "function should be valid for printing"); 218 printIR(OS, F, Banner, "", Brief); 219 return; 220 } 221 222 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 223 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 224 assert(C && "scc should be valid for printing"); 225 std::string Extra = std::string(formatv(" (scc: {0})", C->getName())); 226 printIR(OS, C, Banner, Extra, Brief); 227 return; 228 } 229 230 if (any_isa<const Loop *>(IR)) { 231 const Loop *L = any_cast<const Loop *>(IR); 232 assert(L && "Loop should be valid for printing"); 233 printIR(OS, L, Banner, Brief); 234 return; 235 } 236 llvm_unreachable("Unknown wrapped IR type"); 237 } 238 239 // Return true when this is a pass for which changes should be ignored 240 bool isIgnored(StringRef PassID) { 241 return isSpecialPass(PassID, 242 {"PassManager", "PassAdaptor", "AnalysisManagerProxy"}); 243 } 244 245 } // namespace 246 247 template <typename IRUnitT> 248 ChangeReporter<IRUnitT>::~ChangeReporter<IRUnitT>() { 249 assert(BeforeStack.empty() && "Problem with Change Printer stack."); 250 } 251 252 template <typename IRUnitT> 253 bool ChangeReporter<IRUnitT>::isInterestingFunction(const Function &F) { 254 return isFunctionInPrintList(F.getName()); 255 } 256 257 template <typename IRUnitT> 258 bool ChangeReporter<IRUnitT>::isInterestingPass(StringRef PassID) { 259 if (isIgnored(PassID)) 260 return false; 261 262 static std::unordered_set<std::string> PrintPassNames(PrintPassesList.begin(), 263 PrintPassesList.end()); 264 return PrintPassNames.empty() || PrintPassNames.count(PassID.str()); 265 } 266 267 // Return true when this is a pass on IR for which printing 268 // of changes is desired. 269 template <typename IRUnitT> 270 bool ChangeReporter<IRUnitT>::isInteresting(Any IR, StringRef PassID) { 271 if (!isInterestingPass(PassID)) 272 return false; 273 if (any_isa<const Function *>(IR)) 274 return isInterestingFunction(*any_cast<const Function *>(IR)); 275 return true; 276 } 277 278 template <typename IRUnitT> 279 void ChangeReporter<IRUnitT>::saveIRBeforePass(Any IR, StringRef PassID) { 280 // Always need to place something on the stack because invalidated passes 281 // are not given the IR so it cannot be determined whether the pass was for 282 // something that was filtered out. 283 BeforeStack.emplace_back(); 284 285 if (!isInteresting(IR, PassID)) 286 return; 287 // Is this the initial IR? 288 if (InitialIR) { 289 InitialIR = false; 290 handleInitialIR(IR); 291 } 292 293 // Save the IR representation on the stack. 294 IRUnitT &Data = BeforeStack.back(); 295 generateIRRepresentation(IR, PassID, Data); 296 } 297 298 template <typename IRUnitT> 299 void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) { 300 assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); 301 std::string Name; 302 303 // unwrapModule has inconsistent handling of names for function IRs. 304 if (any_isa<const Function *>(IR)) { 305 const Function *F = any_cast<const Function *>(IR); 306 Name = formatv(" (function: {0})", F->getName()).str(); 307 } else { 308 if (auto UM = unwrapModule(IR)) 309 Name = UM->second; 310 } 311 if (Name == "") 312 Name = " (module)"; 313 314 if (isIgnored(PassID)) 315 handleIgnored(PassID, Name); 316 else if (!isInteresting(IR, PassID)) 317 handleFiltered(PassID, Name); 318 else { 319 // Get the before rep from the stack 320 IRUnitT &Before = BeforeStack.back(); 321 // Create the after rep 322 IRUnitT After; 323 generateIRRepresentation(IR, PassID, After); 324 325 // Was there a change in IR? 326 if (same(Before, After)) 327 omitAfter(PassID, Name); 328 else 329 handleAfter(PassID, Name, Before, After, IR); 330 } 331 BeforeStack.pop_back(); 332 } 333 334 template <typename IRUnitT> 335 void ChangeReporter<IRUnitT>::handleInvalidatedPass(StringRef PassID) { 336 assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); 337 338 // Always flag it as invalidated as we cannot determine when 339 // a pass for a filtered function is invalidated since we do not 340 // get the IR in the call. Also, the output is just alternate 341 // forms of the banner anyway. 342 handleInvalidated(PassID); 343 BeforeStack.pop_back(); 344 } 345 346 template <typename IRUnitT> 347 void ChangeReporter<IRUnitT>::registerRequiredCallbacks( 348 PassInstrumentationCallbacks &PIC) { 349 PIC.registerBeforeNonSkippedPassCallback( 350 [this](StringRef P, Any IR) { saveIRBeforePass(IR, P); }); 351 352 PIC.registerAfterPassCallback( 353 [this](StringRef P, Any IR, const PreservedAnalyses &) { 354 handleIRAfterPass(IR, P); 355 }); 356 PIC.registerAfterPassInvalidatedCallback( 357 [this](StringRef P, const PreservedAnalyses &) { 358 handleInvalidatedPass(P); 359 }); 360 } 361 362 template <typename IRUnitT> 363 TextChangeReporter<IRUnitT>::TextChangeReporter() 364 : ChangeReporter<IRUnitT>(), Out(dbgs()) {} 365 366 template <typename IRUnitT> 367 void TextChangeReporter<IRUnitT>::handleInitialIR(Any IR) { 368 // Always print the module. 369 // Unwrap and print directly to avoid filtering problems in general routines. 370 auto UnwrappedModule = unwrapModule(IR, /*Force=*/true); 371 assert(UnwrappedModule && "Expected module to be unwrapped when forced."); 372 Out << "*** IR Dump At Start: ***" << UnwrappedModule->second << "\n"; 373 UnwrappedModule->first->print(Out, nullptr, 374 /*ShouldPreserveUseListOrder=*/true); 375 } 376 377 template <typename IRUnitT> 378 void TextChangeReporter<IRUnitT>::omitAfter(StringRef PassID, 379 std::string &Name) { 380 Out << formatv("*** IR Dump After {0}{1} omitted because no change ***\n", 381 PassID, Name); 382 } 383 384 template <typename IRUnitT> 385 void TextChangeReporter<IRUnitT>::handleInvalidated(StringRef PassID) { 386 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID); 387 } 388 389 template <typename IRUnitT> 390 void TextChangeReporter<IRUnitT>::handleFiltered(StringRef PassID, 391 std::string &Name) { 392 SmallString<20> Banner = 393 formatv("*** IR Dump After {0}{1} filtered out ***\n", PassID, Name); 394 Out << Banner; 395 } 396 397 template <typename IRUnitT> 398 void TextChangeReporter<IRUnitT>::handleIgnored(StringRef PassID, 399 std::string &Name) { 400 Out << formatv("*** IR Pass {0}{1} ignored ***\n", PassID, Name); 401 } 402 403 IRChangedPrinter::~IRChangedPrinter() {} 404 405 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { 406 if (PrintChanged) 407 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC); 408 } 409 410 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID, 411 std::string &Output) { 412 raw_string_ostream OS(Output); 413 // use the after banner for all cases so it will match 414 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); 415 unwrapAndPrint(OS, IR, Banner, forcePrintModuleIR(), 416 /*Brief=*/false, /*ShouldPreserveUseListOrder=*/true); 417 418 OS.str(); 419 } 420 421 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name, 422 const std::string &Before, 423 const std::string &After, Any) { 424 assert(After.find("*** IR Dump") == 0 && "Unexpected banner format."); 425 StringRef AfterRef = After; 426 StringRef Banner = 427 AfterRef.take_until([](char C) -> bool { return C == '\n'; }); 428 429 // Report the IR before the changes when requested. 430 if (PrintChangedBefore) { 431 Out << "*** IR Dump Before" << Banner.substr(17); 432 // LazyCallGraph::SCC already has "(scc:..." in banner so only add 433 // in the name if it isn't already there. 434 if (Name.substr(0, 6) != " (scc:" && !forcePrintModuleIR()) 435 Out << Name; 436 437 StringRef BeforeRef = Before; 438 Out << BeforeRef.substr(Banner.size()); 439 } 440 441 Out << Banner; 442 443 // LazyCallGraph::SCC already has "(scc:..." in banner so only add 444 // in the name if it isn't already there. 445 if (Name.substr(0, 6) != " (scc:" && !forcePrintModuleIR()) 446 Out << Name; 447 448 Out << After.substr(Banner.size()); 449 } 450 451 bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) { 452 return S1 == S2; 453 } 454 455 PrintIRInstrumentation::~PrintIRInstrumentation() { 456 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); 457 } 458 459 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { 460 assert(StoreModuleDesc); 461 const Module *M = nullptr; 462 std::string Extra; 463 if (auto UnwrappedModule = unwrapModule(IR)) 464 std::tie(M, Extra) = UnwrappedModule.getValue(); 465 ModuleDescStack.emplace_back(M, Extra, PassID); 466 } 467 468 PrintIRInstrumentation::PrintModuleDesc 469 PrintIRInstrumentation::popModuleDesc(StringRef PassID) { 470 assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); 471 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); 472 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); 473 return ModuleDesc; 474 } 475 476 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 477 if (isIgnored(PassID)) 478 return; 479 480 // Saving Module for AfterPassInvalidated operations. 481 // Note: here we rely on a fact that we do not change modules while 482 // traversing the pipeline, so the latest captured module is good 483 // for all print operations that has not happen yet. 484 if (StoreModuleDesc && shouldPrintAfterPass(PassID)) 485 pushModuleDesc(PassID, IR); 486 487 if (!shouldPrintBeforePass(PassID)) 488 return; 489 490 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID); 491 unwrapAndPrint(dbgs(), IR, Banner, forcePrintModuleIR()); 492 return; 493 } 494 495 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 496 if (isIgnored(PassID)) 497 return; 498 499 if (!shouldPrintAfterPass(PassID)) 500 return; 501 502 if (StoreModuleDesc) 503 popModuleDesc(PassID); 504 505 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID); 506 unwrapAndPrint(dbgs(), IR, Banner, forcePrintModuleIR()); 507 } 508 509 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 510 StringRef PassName = PIC->getPassNameForClassName(PassID); 511 if (!StoreModuleDesc || !shouldPrintAfterPass(PassName)) 512 return; 513 514 if (isIgnored(PassID)) 515 return; 516 517 const Module *M; 518 std::string Extra; 519 StringRef StoredPassID; 520 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID); 521 // Additional filtering (e.g. -filter-print-func) can lead to module 522 // printing being skipped. 523 if (!M) 524 return; 525 526 SmallString<20> Banner = 527 formatv("*** IR Dump After {0} *** invalidated: ", PassID); 528 printIR(dbgs(), M, Banner, Extra); 529 } 530 531 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) { 532 if (shouldPrintBeforeAll()) 533 return true; 534 535 StringRef PassName = PIC->getPassNameForClassName(PassID); 536 for (const auto &P : printBeforePasses()) { 537 if (PassName == P) 538 return true; 539 } 540 return false; 541 } 542 543 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) { 544 if (shouldPrintAfterAll()) 545 return true; 546 547 StringRef PassName = PIC->getPassNameForClassName(PassID); 548 for (const auto &P : printAfterPasses()) { 549 if (PassName == P) 550 return true; 551 } 552 return false; 553 } 554 555 void PrintIRInstrumentation::registerCallbacks( 556 PassInstrumentationCallbacks &PIC) { 557 this->PIC = &PIC; 558 559 // BeforePass callback is not just for printing, it also saves a Module 560 // for later use in AfterPassInvalidated. 561 StoreModuleDesc = forcePrintModuleIR() && shouldPrintAfterSomePass(); 562 if (shouldPrintBeforeSomePass() || StoreModuleDesc) 563 PIC.registerBeforeNonSkippedPassCallback( 564 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 565 566 if (shouldPrintAfterSomePass()) { 567 PIC.registerAfterPassCallback( 568 [this](StringRef P, Any IR, const PreservedAnalyses &) { 569 this->printAfterPass(P, IR); 570 }); 571 PIC.registerAfterPassInvalidatedCallback( 572 [this](StringRef P, const PreservedAnalyses &) { 573 this->printAfterPassInvalidated(P); 574 }); 575 } 576 } 577 578 void OptNoneInstrumentation::registerCallbacks( 579 PassInstrumentationCallbacks &PIC) { 580 PIC.registerShouldRunOptionalPassCallback( 581 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); }); 582 } 583 584 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) { 585 const Function *F = nullptr; 586 if (any_isa<const Function *>(IR)) { 587 F = any_cast<const Function *>(IR); 588 } else if (any_isa<const Loop *>(IR)) { 589 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 590 } 591 bool ShouldRun = !(F && F->hasOptNone()); 592 if (!ShouldRun && DebugLogging) { 593 errs() << "Skipping pass " << PassID << " on " << F->getName() 594 << " due to optnone attribute\n"; 595 } 596 return ShouldRun; 597 } 598 599 static std::string getBisectDescription(Any IR) { 600 if (any_isa<const Module *>(IR)) { 601 const Module *M = any_cast<const Module *>(IR); 602 assert(M && "module should be valid for printing"); 603 return "module (" + M->getName().str() + ")"; 604 } 605 606 if (any_isa<const Function *>(IR)) { 607 const Function *F = any_cast<const Function *>(IR); 608 assert(F && "function should be valid for printing"); 609 return "function (" + F->getName().str() + ")"; 610 } 611 612 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 613 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 614 assert(C && "scc should be valid for printing"); 615 return "SCC " + C->getName(); 616 } 617 618 if (any_isa<const Loop *>(IR)) { 619 return "loop"; 620 } 621 622 llvm_unreachable("Unknown wrapped IR type"); 623 } 624 625 void OptBisectInstrumentation::registerCallbacks( 626 PassInstrumentationCallbacks &PIC) { 627 if (!isEnabled()) 628 return; 629 630 PIC.registerShouldRunOptionalPassCallback([this](StringRef PassID, Any IR) { 631 return isIgnored(PassID) || checkPass(PassID, getBisectDescription(IR)); 632 }); 633 } 634 635 void PrintPassInstrumentation::registerCallbacks( 636 PassInstrumentationCallbacks &PIC) { 637 if (!DebugLogging) 638 return; 639 640 std::vector<StringRef> SpecialPasses = {"PassManager"}; 641 if (!DebugPMVerbose) 642 SpecialPasses.emplace_back("PassAdaptor"); 643 644 PIC.registerBeforeSkippedPassCallback( 645 [SpecialPasses](StringRef PassID, Any IR) { 646 assert(!isSpecialPass(PassID, SpecialPasses) && 647 "Unexpectedly skipping special pass"); 648 649 dbgs() << "Skipping pass: " << PassID << " on "; 650 unwrapAndPrint(dbgs(), IR, "", false, true); 651 }); 652 653 PIC.registerBeforeNonSkippedPassCallback( 654 [SpecialPasses](StringRef PassID, Any IR) { 655 if (isSpecialPass(PassID, SpecialPasses)) 656 return; 657 658 dbgs() << "Running pass: " << PassID << " on "; 659 unwrapAndPrint(dbgs(), IR, "", false, true); 660 }); 661 662 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) { 663 dbgs() << "Running analysis: " << PassID << " on "; 664 unwrapAndPrint(dbgs(), IR, "", false, true); 665 }); 666 } 667 668 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F, 669 bool TrackBBLifetime) { 670 if (TrackBBLifetime) 671 BBGuards = DenseMap<intptr_t, BBGuard>(F->size()); 672 for (const auto &BB : *F) { 673 if (BBGuards) 674 BBGuards->try_emplace(intptr_t(&BB), &BB); 675 for (auto *Succ : successors(&BB)) { 676 Graph[&BB][Succ]++; 677 if (BBGuards) 678 BBGuards->try_emplace(intptr_t(Succ), Succ); 679 } 680 } 681 } 682 683 static void printBBName(raw_ostream &out, const BasicBlock *BB) { 684 if (BB->hasName()) { 685 out << BB->getName() << "<" << BB << ">"; 686 return; 687 } 688 689 if (!BB->getParent()) { 690 out << "unnamed_removed<" << BB << ">"; 691 return; 692 } 693 694 if (BB == &BB->getParent()->getEntryBlock()) { 695 out << "entry" 696 << "<" << BB << ">"; 697 return; 698 } 699 700 unsigned FuncOrderBlockNum = 0; 701 for (auto &FuncBB : *BB->getParent()) { 702 if (&FuncBB == BB) 703 break; 704 FuncOrderBlockNum++; 705 } 706 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">"; 707 } 708 709 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out, 710 const CFG &Before, 711 const CFG &After) { 712 assert(!After.isPoisoned()); 713 714 // Print function name. 715 const CFG *FuncGraph = nullptr; 716 if (!After.Graph.empty()) 717 FuncGraph = &After; 718 else if (!Before.isPoisoned() && !Before.Graph.empty()) 719 FuncGraph = &Before; 720 721 if (FuncGraph) 722 out << "In function @" 723 << FuncGraph->Graph.begin()->first->getParent()->getName() << "\n"; 724 725 if (Before.isPoisoned()) { 726 out << "Some blocks were deleted\n"; 727 return; 728 } 729 730 // Find and print graph differences. 731 if (Before.Graph.size() != After.Graph.size()) 732 out << "Different number of non-leaf basic blocks: before=" 733 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n"; 734 735 for (auto &BB : Before.Graph) { 736 auto BA = After.Graph.find(BB.first); 737 if (BA == After.Graph.end()) { 738 out << "Non-leaf block "; 739 printBBName(out, BB.first); 740 out << " is removed (" << BB.second.size() << " successors)\n"; 741 } 742 } 743 744 for (auto &BA : After.Graph) { 745 auto BB = Before.Graph.find(BA.first); 746 if (BB == Before.Graph.end()) { 747 out << "Non-leaf block "; 748 printBBName(out, BA.first); 749 out << " is added (" << BA.second.size() << " successors)\n"; 750 continue; 751 } 752 753 if (BB->second == BA.second) 754 continue; 755 756 out << "Different successors of block "; 757 printBBName(out, BA.first); 758 out << " (unordered):\n"; 759 out << "- before (" << BB->second.size() << "): "; 760 for (auto &SuccB : BB->second) { 761 printBBName(out, SuccB.first); 762 if (SuccB.second != 1) 763 out << "(" << SuccB.second << "), "; 764 else 765 out << ", "; 766 } 767 out << "\n"; 768 out << "- after (" << BA.second.size() << "): "; 769 for (auto &SuccA : BA.second) { 770 printBBName(out, SuccA.first); 771 if (SuccA.second != 1) 772 out << "(" << SuccA.second << "), "; 773 else 774 out << ", "; 775 } 776 out << "\n"; 777 } 778 } 779 780 void PreservedCFGCheckerInstrumentation::registerCallbacks( 781 PassInstrumentationCallbacks &PIC) { 782 if (!VerifyPreservedCFG) 783 return; 784 785 PIC.registerBeforeNonSkippedPassCallback([this](StringRef P, Any IR) { 786 if (any_isa<const Function *>(IR)) 787 GraphStackBefore.emplace_back(P, CFG(any_cast<const Function *>(IR))); 788 else 789 GraphStackBefore.emplace_back(P, None); 790 }); 791 792 PIC.registerAfterPassInvalidatedCallback( 793 [this](StringRef P, const PreservedAnalyses &PassPA) { 794 auto Before = GraphStackBefore.pop_back_val(); 795 assert(Before.first == P && 796 "Before and After callbacks must correspond"); 797 (void)Before; 798 }); 799 800 PIC.registerAfterPassCallback([this](StringRef P, Any IR, 801 const PreservedAnalyses &PassPA) { 802 auto Before = GraphStackBefore.pop_back_val(); 803 assert(Before.first == P && "Before and After callbacks must correspond"); 804 auto &GraphBefore = Before.second; 805 806 if (!PassPA.allAnalysesInSetPreserved<CFGAnalyses>()) 807 return; 808 809 if (any_isa<const Function *>(IR)) { 810 assert(GraphBefore && "Must be built in BeforePassCallback"); 811 CFG GraphAfter(any_cast<const Function *>(IR), false /* NeedsGuard */); 812 if (GraphAfter == *GraphBefore) 813 return; 814 815 dbgs() << "Error: " << P 816 << " reported it preserved CFG, but changes detected:\n"; 817 CFG::printDiff(dbgs(), *GraphBefore, GraphAfter); 818 report_fatal_error(Twine("Preserved CFG changed by ", P)); 819 } 820 }); 821 } 822 823 void VerifyInstrumentation::registerCallbacks( 824 PassInstrumentationCallbacks &PIC) { 825 PIC.registerAfterPassCallback( 826 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { 827 if (isIgnored(P) || P == "VerifierPass") 828 return; 829 if (any_isa<const Function *>(IR) || any_isa<const Loop *>(IR)) { 830 const Function *F; 831 if (any_isa<const Loop *>(IR)) 832 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 833 else 834 F = any_cast<const Function *>(IR); 835 if (DebugLogging) 836 dbgs() << "Verifying function " << F->getName() << "\n"; 837 838 if (verifyFunction(*F)) 839 report_fatal_error("Broken function found, compilation aborted!"); 840 } else if (any_isa<const Module *>(IR) || 841 any_isa<const LazyCallGraph::SCC *>(IR)) { 842 const Module *M; 843 if (any_isa<const LazyCallGraph::SCC *>(IR)) 844 M = any_cast<const LazyCallGraph::SCC *>(IR) 845 ->begin() 846 ->getFunction() 847 .getParent(); 848 else 849 M = any_cast<const Module *>(IR); 850 if (DebugLogging) 851 dbgs() << "Verifying module " << M->getName() << "\n"; 852 853 if (verifyModule(*M)) 854 report_fatal_error("Broken module found, compilation aborted!"); 855 } 856 }); 857 } 858 859 void StandardInstrumentations::registerCallbacks( 860 PassInstrumentationCallbacks &PIC) { 861 PrintIR.registerCallbacks(PIC); 862 PrintPass.registerCallbacks(PIC); 863 TimePasses.registerCallbacks(PIC); 864 OptNone.registerCallbacks(PIC); 865 OptBisect.registerCallbacks(PIC); 866 PreservedCFGChecker.registerCallbacks(PIC); 867 PrintChangedIR.registerCallbacks(PIC); 868 if (VerifyEach) 869 Verify.registerCallbacks(PIC); 870 } 871 872 namespace llvm { 873 874 template class ChangeReporter<std::string>; 875 template class TextChangeReporter<std::string>; 876 877 } // namespace llvm 878