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