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