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