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/LegacyPassManager.h" 24 #include "llvm/IR/Module.h" 25 #include "llvm/IR/PassInstrumentation.h" 26 #include "llvm/IR/PassManager.h" 27 #include "llvm/IR/PrintPasses.h" 28 #include "llvm/IR/Verifier.h" 29 #include "llvm/Support/CommandLine.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/FormatVariadic.h" 32 #include "llvm/Support/MemoryBuffer.h" 33 #include "llvm/Support/Program.h" 34 #include "llvm/Support/raw_ostream.h" 35 #include <unordered_set> 36 #include <vector> 37 38 using namespace llvm; 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 static cl::opt<bool> 56 DebugPassStructure("debug-pass-structure", cl::Hidden, cl::init(false), 57 cl::desc("Print pass structure information.")); 58 59 // An option that prints out the IR after passes, similar to 60 // -print-after-all except that it only prints the IR after passes that 61 // change the IR. Those passes that do not make changes to the IR are 62 // reported as not making any changes. In addition, the initial IR is 63 // also reported. Other hidden options affect the output from this 64 // option. -filter-passes will limit the output to the named passes 65 // that actually change the IR and other passes are reported as filtered out. 66 // The specified passes will either be reported as making no changes (with 67 // no IR reported) or the changed IR will be reported. Also, the 68 // -filter-print-funcs and -print-module-scope options will do similar 69 // filtering based on function name, reporting changed IRs as functions(or 70 // modules if -print-module-scope is specified) for a particular function 71 // or indicating that the IR has been filtered out. The extra options 72 // can be combined, allowing only changed IRs for certain passes on certain 73 // functions to be reported in different formats, with the rest being 74 // reported as filtered out. The -print-before-changed option will print 75 // the IR as it was before each pass that changed it. The optional 76 // value of quiet will only report when the IR changes, suppressing 77 // all other messages, including the initial IR. The values "diff" and 78 // "diff-quiet" will present the changes in a form similar to a patch, in 79 // either verbose or quiet mode, respectively. The lines that are removed 80 // and added are prefixed with '-' and '+', respectively. The 81 // -filter-print-funcs and -filter-passes can be used to filter the output. 82 // This reporter relies on the linux diff utility to do comparisons and 83 // insert the prefixes. For systems that do not have the necessary 84 // facilities, the error message will be shown in place of the expected output. 85 // 86 enum class ChangePrinter { 87 NoChangePrinter, 88 PrintChangedVerbose, 89 PrintChangedQuiet, 90 PrintChangedDiffVerbose, 91 PrintChangedDiffQuiet, 92 PrintChangedColourDiffVerbose, 93 PrintChangedColourDiffQuiet 94 }; 95 static cl::opt<ChangePrinter> PrintChanged( 96 "print-changed", cl::desc("Print changed IRs"), cl::Hidden, 97 cl::ValueOptional, cl::init(ChangePrinter::NoChangePrinter), 98 cl::values( 99 clEnumValN(ChangePrinter::PrintChangedQuiet, "quiet", 100 "Run in quiet mode"), 101 clEnumValN(ChangePrinter::PrintChangedDiffVerbose, "diff", 102 "Display patch-like changes"), 103 clEnumValN(ChangePrinter::PrintChangedDiffQuiet, "diff-quiet", 104 "Display patch-like changes in quiet mode"), 105 clEnumValN(ChangePrinter::PrintChangedColourDiffVerbose, "cdiff", 106 "Display patch-like changes with color"), 107 clEnumValN(ChangePrinter::PrintChangedColourDiffQuiet, "cdiff-quiet", 108 "Display patch-like changes in quiet mode with color"), 109 // Sentinel value for unspecified option. 110 clEnumValN(ChangePrinter::PrintChangedVerbose, "", ""))); 111 112 // An option that supports the -print-changed option. See 113 // the description for -print-changed for an explanation of the use 114 // of this option. Note that this option has no effect without -print-changed. 115 static cl::list<std::string> 116 PrintPassesList("filter-passes", cl::value_desc("pass names"), 117 cl::desc("Only consider IR changes for passes whose names " 118 "match for the print-changed option"), 119 cl::CommaSeparated, cl::Hidden); 120 // An option that supports the -print-changed option. See 121 // the description for -print-changed for an explanation of the use 122 // of this option. Note that this option has no effect without -print-changed. 123 static cl::opt<bool> 124 PrintChangedBefore("print-before-changed", 125 cl::desc("Print before passes that change them"), 126 cl::init(false), cl::Hidden); 127 128 // An option for specifying the diff used by print-changed=[diff | diff-quiet] 129 static cl::opt<std::string> 130 DiffBinary("print-changed-diff-path", cl::Hidden, cl::init("diff"), 131 cl::desc("system diff used by change reporters")); 132 133 namespace { 134 135 // Perform a system based diff between \p Before and \p After, using 136 // \p OldLineFormat, \p NewLineFormat, and \p UnchangedLineFormat 137 // to control the formatting of the output. Return an error message 138 // for any failures instead of the diff. 139 std::string doSystemDiff(StringRef Before, StringRef After, 140 StringRef OldLineFormat, StringRef NewLineFormat, 141 StringRef UnchangedLineFormat) { 142 StringRef SR[2]{Before, After}; 143 // Store the 2 bodies into temporary files and call diff on them 144 // to get the body of the node. 145 const unsigned NumFiles = 3; 146 std::string FileName[NumFiles]; 147 int FD[NumFiles]{-1, -1, -1}; 148 for (unsigned I = 0; I < NumFiles; ++I) { 149 if (FD[I] == -1) { 150 SmallVector<char, 200> SV; 151 std::error_code EC = 152 sys::fs::createTemporaryFile("tmpdiff", "txt", FD[I], SV); 153 if (EC) 154 return "Unable to create temporary file."; 155 FileName[I] = Twine(SV).str(); 156 } 157 // The third file is used as the result of the diff. 158 if (I == NumFiles - 1) 159 break; 160 161 std::error_code EC = sys::fs::openFileForWrite(FileName[I], FD[I]); 162 if (EC) 163 return "Unable to open temporary file for writing."; 164 165 raw_fd_ostream OutStream(FD[I], /*shouldClose=*/true); 166 if (FD[I] == -1) 167 return "Error opening file for writing."; 168 OutStream << SR[I]; 169 } 170 171 static ErrorOr<std::string> DiffExe = sys::findProgramByName(DiffBinary); 172 if (!DiffExe) 173 return "Unable to find diff executable."; 174 175 SmallString<128> OLF = formatv("--old-line-format={0}", OldLineFormat); 176 SmallString<128> NLF = formatv("--new-line-format={0}", NewLineFormat); 177 SmallString<128> ULF = 178 formatv("--unchanged-line-format={0}", UnchangedLineFormat); 179 180 StringRef Args[] = {"-w", "-d", OLF, NLF, ULF, FileName[0], FileName[1]}; 181 Optional<StringRef> Redirects[] = {None, StringRef(FileName[2]), None}; 182 int Result = sys::ExecuteAndWait(*DiffExe, Args, None, Redirects); 183 if (Result < 0) 184 return "Error executing system diff."; 185 std::string Diff; 186 auto B = MemoryBuffer::getFile(FileName[2]); 187 if (B && *B) 188 Diff = (*B)->getBuffer().str(); 189 else 190 return "Unable to read result."; 191 192 // Clean up. 193 for (unsigned I = 0; I < NumFiles; ++I) { 194 std::error_code EC = sys::fs::remove(FileName[I]); 195 if (EC) 196 return "Unable to remove temporary file."; 197 } 198 return Diff; 199 } 200 201 /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match 202 /// certain global filters. Will never return nullptr if \p Force is true. 203 const Module *unwrapModule(Any IR, bool Force = false) { 204 if (any_isa<const Module *>(IR)) 205 return any_cast<const Module *>(IR); 206 207 if (any_isa<const Function *>(IR)) { 208 const Function *F = any_cast<const Function *>(IR); 209 if (!Force && !isFunctionInPrintList(F->getName())) 210 return nullptr; 211 212 return F->getParent(); 213 } 214 215 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 216 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 217 for (const LazyCallGraph::Node &N : *C) { 218 const Function &F = N.getFunction(); 219 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) { 220 return F.getParent(); 221 } 222 } 223 assert(!Force && "Expected a module"); 224 return nullptr; 225 } 226 227 if (any_isa<const Loop *>(IR)) { 228 const Loop *L = any_cast<const Loop *>(IR); 229 const Function *F = L->getHeader()->getParent(); 230 if (!Force && !isFunctionInPrintList(F->getName())) 231 return nullptr; 232 return F->getParent(); 233 } 234 235 llvm_unreachable("Unknown IR unit"); 236 } 237 238 void printIR(raw_ostream &OS, const Function *F) { 239 if (!isFunctionInPrintList(F->getName())) 240 return; 241 OS << *F; 242 } 243 244 void printIR(raw_ostream &OS, const Module *M, 245 bool ShouldPreserveUseListOrder = false) { 246 if (isFunctionInPrintList("*") || forcePrintModuleIR()) { 247 M->print(OS, nullptr, ShouldPreserveUseListOrder); 248 } else { 249 for (const auto &F : M->functions()) { 250 printIR(OS, &F); 251 } 252 } 253 } 254 255 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) { 256 for (const LazyCallGraph::Node &N : *C) { 257 const Function &F = N.getFunction(); 258 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 259 F.print(OS); 260 } 261 } 262 } 263 264 void printIR(raw_ostream &OS, const Loop *L) { 265 const Function *F = L->getHeader()->getParent(); 266 if (!isFunctionInPrintList(F->getName())) 267 return; 268 printLoop(const_cast<Loop &>(*L), OS); 269 } 270 271 std::string getIRName(Any IR) { 272 if (any_isa<const Module *>(IR)) 273 return "[module]"; 274 275 if (any_isa<const Function *>(IR)) { 276 const Function *F = any_cast<const Function *>(IR); 277 return F->getName().str(); 278 } 279 280 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 281 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 282 return C->getName(); 283 } 284 285 if (any_isa<const Loop *>(IR)) { 286 const Loop *L = any_cast<const Loop *>(IR); 287 std::string S; 288 raw_string_ostream OS(S); 289 L->print(OS, /*Verbose*/ false, /*PrintNested*/ false); 290 return OS.str(); 291 } 292 293 llvm_unreachable("Unknown wrapped IR type"); 294 } 295 296 bool moduleContainsFilterPrintFunc(const Module &M) { 297 return any_of(M.functions(), 298 [](const Function &F) { 299 return isFunctionInPrintList(F.getName()); 300 }) || 301 isFunctionInPrintList("*"); 302 } 303 304 bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) { 305 return any_of(C, 306 [](const LazyCallGraph::Node &N) { 307 return isFunctionInPrintList(N.getName()); 308 }) || 309 isFunctionInPrintList("*"); 310 } 311 312 bool shouldPrintIR(Any IR) { 313 if (any_isa<const Module *>(IR)) { 314 const Module *M = any_cast<const Module *>(IR); 315 return moduleContainsFilterPrintFunc(*M); 316 } 317 318 if (any_isa<const Function *>(IR)) { 319 const Function *F = any_cast<const Function *>(IR); 320 return isFunctionInPrintList(F->getName()); 321 } 322 323 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 324 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 325 return sccContainsFilterPrintFunc(*C); 326 } 327 328 if (any_isa<const Loop *>(IR)) { 329 const Loop *L = any_cast<const Loop *>(IR); 330 return isFunctionInPrintList(L->getHeader()->getParent()->getName()); 331 } 332 llvm_unreachable("Unknown wrapped IR type"); 333 } 334 335 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 336 /// llvm::Any and does actual print job. 337 void unwrapAndPrint(raw_ostream &OS, Any IR, 338 bool ShouldPreserveUseListOrder = false) { 339 if (!shouldPrintIR(IR)) 340 return; 341 342 if (forcePrintModuleIR()) { 343 auto *M = unwrapModule(IR); 344 assert(M && "should have unwrapped module"); 345 printIR(OS, M, ShouldPreserveUseListOrder); 346 return; 347 } 348 349 if (any_isa<const Module *>(IR)) { 350 const Module *M = any_cast<const Module *>(IR); 351 printIR(OS, M, ShouldPreserveUseListOrder); 352 return; 353 } 354 355 if (any_isa<const Function *>(IR)) { 356 const Function *F = any_cast<const Function *>(IR); 357 printIR(OS, F); 358 return; 359 } 360 361 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 362 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 363 printIR(OS, C); 364 return; 365 } 366 367 if (any_isa<const Loop *>(IR)) { 368 const Loop *L = any_cast<const Loop *>(IR); 369 printIR(OS, L); 370 return; 371 } 372 llvm_unreachable("Unknown wrapped IR type"); 373 } 374 375 // Return true when this is a pass for which changes should be ignored 376 bool isIgnored(StringRef PassID) { 377 return isSpecialPass(PassID, 378 {"PassManager", "PassAdaptor", "AnalysisManagerProxy", 379 "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass"}); 380 } 381 382 } // namespace 383 384 template <typename IRUnitT> 385 ChangeReporter<IRUnitT>::~ChangeReporter<IRUnitT>() { 386 assert(BeforeStack.empty() && "Problem with Change Printer stack."); 387 } 388 389 template <typename IRUnitT> 390 bool ChangeReporter<IRUnitT>::isInterestingFunction(const Function &F) { 391 return isFunctionInPrintList(F.getName()); 392 } 393 394 template <typename IRUnitT> 395 bool ChangeReporter<IRUnitT>::isInterestingPass(StringRef PassID) { 396 if (isIgnored(PassID)) 397 return false; 398 399 static std::unordered_set<std::string> PrintPassNames(PrintPassesList.begin(), 400 PrintPassesList.end()); 401 return PrintPassNames.empty() || PrintPassNames.count(PassID.str()); 402 } 403 404 // Return true when this is a pass on IR for which printing 405 // of changes is desired. 406 template <typename IRUnitT> 407 bool ChangeReporter<IRUnitT>::isInteresting(Any IR, StringRef PassID) { 408 if (!isInterestingPass(PassID)) 409 return false; 410 if (any_isa<const Function *>(IR)) 411 return isInterestingFunction(*any_cast<const Function *>(IR)); 412 return true; 413 } 414 415 template <typename IRUnitT> 416 void ChangeReporter<IRUnitT>::saveIRBeforePass(Any IR, StringRef PassID) { 417 // Always need to place something on the stack because invalidated passes 418 // are not given the IR so it cannot be determined whether the pass was for 419 // something that was filtered out. 420 BeforeStack.emplace_back(); 421 422 if (!isInteresting(IR, PassID)) 423 return; 424 // Is this the initial IR? 425 if (InitialIR) { 426 InitialIR = false; 427 if (VerboseMode) 428 handleInitialIR(IR); 429 } 430 431 // Save the IR representation on the stack. 432 IRUnitT &Data = BeforeStack.back(); 433 generateIRRepresentation(IR, PassID, Data); 434 } 435 436 template <typename IRUnitT> 437 void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) { 438 assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); 439 440 std::string Name = getIRName(IR); 441 442 if (isIgnored(PassID)) { 443 if (VerboseMode) 444 handleIgnored(PassID, Name); 445 } else if (!isInteresting(IR, PassID)) { 446 if (VerboseMode) 447 handleFiltered(PassID, Name); 448 } else { 449 // Get the before rep from the stack 450 IRUnitT &Before = BeforeStack.back(); 451 // Create the after rep 452 IRUnitT After; 453 generateIRRepresentation(IR, PassID, After); 454 455 // Was there a change in IR? 456 if (same(Before, After)) { 457 if (VerboseMode) 458 omitAfter(PassID, Name); 459 } else 460 handleAfter(PassID, Name, Before, After, IR); 461 } 462 BeforeStack.pop_back(); 463 } 464 465 template <typename IRUnitT> 466 void ChangeReporter<IRUnitT>::handleInvalidatedPass(StringRef PassID) { 467 assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); 468 469 // Always flag it as invalidated as we cannot determine when 470 // a pass for a filtered function is invalidated since we do not 471 // get the IR in the call. Also, the output is just alternate 472 // forms of the banner anyway. 473 if (VerboseMode) 474 handleInvalidated(PassID); 475 BeforeStack.pop_back(); 476 } 477 478 template <typename IRUnitT> 479 void ChangeReporter<IRUnitT>::registerRequiredCallbacks( 480 PassInstrumentationCallbacks &PIC) { 481 PIC.registerBeforeNonSkippedPassCallback( 482 [this](StringRef P, Any IR) { saveIRBeforePass(IR, P); }); 483 484 PIC.registerAfterPassCallback( 485 [this](StringRef P, Any IR, const PreservedAnalyses &) { 486 handleIRAfterPass(IR, P); 487 }); 488 PIC.registerAfterPassInvalidatedCallback( 489 [this](StringRef P, const PreservedAnalyses &) { 490 handleInvalidatedPass(P); 491 }); 492 } 493 494 ChangedBlockData::ChangedBlockData(const BasicBlock &B) 495 : Label(B.getName().str()) { 496 raw_string_ostream SS(Body); 497 B.print(SS, nullptr, true, true); 498 } 499 500 template <typename IRUnitT> 501 TextChangeReporter<IRUnitT>::TextChangeReporter(bool Verbose) 502 : ChangeReporter<IRUnitT>(Verbose), Out(dbgs()) {} 503 504 template <typename IRUnitT> 505 void TextChangeReporter<IRUnitT>::handleInitialIR(Any IR) { 506 // Always print the module. 507 // Unwrap and print directly to avoid filtering problems in general routines. 508 auto *M = unwrapModule(IR, /*Force=*/true); 509 assert(M && "Expected module to be unwrapped when forced."); 510 Out << "*** IR Dump At Start ***\n"; 511 M->print(Out, nullptr, 512 /*ShouldPreserveUseListOrder=*/true); 513 } 514 515 template <typename IRUnitT> 516 void TextChangeReporter<IRUnitT>::omitAfter(StringRef PassID, 517 std::string &Name) { 518 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n", 519 PassID, Name); 520 } 521 522 template <typename IRUnitT> 523 void TextChangeReporter<IRUnitT>::handleInvalidated(StringRef PassID) { 524 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID); 525 } 526 527 template <typename IRUnitT> 528 void TextChangeReporter<IRUnitT>::handleFiltered(StringRef PassID, 529 std::string &Name) { 530 SmallString<20> Banner = 531 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name); 532 Out << Banner; 533 } 534 535 template <typename IRUnitT> 536 void TextChangeReporter<IRUnitT>::handleIgnored(StringRef PassID, 537 std::string &Name) { 538 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name); 539 } 540 541 IRChangedPrinter::~IRChangedPrinter() {} 542 543 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { 544 if (PrintChanged == ChangePrinter::PrintChangedVerbose || 545 PrintChanged == ChangePrinter::PrintChangedQuiet) 546 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC); 547 } 548 549 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID, 550 std::string &Output) { 551 raw_string_ostream OS(Output); 552 unwrapAndPrint(OS, IR, 553 /*ShouldPreserveUseListOrder=*/true); 554 OS.str(); 555 } 556 557 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name, 558 const std::string &Before, 559 const std::string &After, Any) { 560 // Report the IR before the changes when requested. 561 if (PrintChangedBefore) 562 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n" 563 << Before; 564 565 // We might not get anything to print if we only want to print a specific 566 // function but it gets deleted. 567 if (After.empty()) { 568 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n"; 569 return; 570 } 571 572 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After; 573 } 574 575 bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) { 576 return S1 == S2; 577 } 578 579 template <typename IRData> 580 void OrderedChangedData<IRData>::report( 581 const OrderedChangedData &Before, const OrderedChangedData &After, 582 function_ref<void(const IRData *, const IRData *)> HandlePair) { 583 const auto &BFD = Before.getData(); 584 const auto &AFD = After.getData(); 585 std::vector<std::string>::const_iterator BI = Before.getOrder().begin(); 586 std::vector<std::string>::const_iterator BE = Before.getOrder().end(); 587 std::vector<std::string>::const_iterator AI = After.getOrder().begin(); 588 std::vector<std::string>::const_iterator AE = After.getOrder().end(); 589 590 auto handlePotentiallyRemovedIRData = [&](std::string S) { 591 // The order in LLVM may have changed so check if still exists. 592 if (!AFD.count(S)) { 593 // This has been removed. 594 HandlePair(&BFD.find(*BI)->getValue(), nullptr); 595 } 596 }; 597 auto handleNewIRData = [&](std::vector<const IRData *> &Q) { 598 // Print out any queued up new sections 599 for (const IRData *NBI : Q) 600 HandlePair(nullptr, NBI); 601 Q.clear(); 602 }; 603 604 // Print out the IRData in the after order, with before ones interspersed 605 // appropriately (ie, somewhere near where they were in the before list). 606 // Start at the beginning of both lists. Loop through the 607 // after list. If an element is common, then advance in the before list 608 // reporting the removed ones until the common one is reached. Report any 609 // queued up new ones and then report the common one. If an element is not 610 // common, then enqueue it for reporting. When the after list is exhausted, 611 // loop through the before list, reporting any removed ones. Finally, 612 // report the rest of the enqueued new ones. 613 std::vector<const IRData *> NewIRDataQueue; 614 while (AI != AE) { 615 if (!BFD.count(*AI)) { 616 // This section is new so place it in the queue. This will cause it 617 // to be reported after deleted sections. 618 NewIRDataQueue.emplace_back(&AFD.find(*AI)->getValue()); 619 ++AI; 620 continue; 621 } 622 // This section is in both; advance and print out any before-only 623 // until we get to it. 624 while (*BI != *AI) { 625 handlePotentiallyRemovedIRData(*BI); 626 ++BI; 627 } 628 // Report any new sections that were queued up and waiting. 629 handleNewIRData(NewIRDataQueue); 630 631 const IRData &AData = AFD.find(*AI)->getValue(); 632 const IRData &BData = BFD.find(*AI)->getValue(); 633 HandlePair(&BData, &AData); 634 ++BI; 635 ++AI; 636 } 637 638 // Check any remaining before sections to see if they have been removed 639 while (BI != BE) { 640 handlePotentiallyRemovedIRData(*BI); 641 ++BI; 642 } 643 644 handleNewIRData(NewIRDataQueue); 645 } 646 647 void ChangedIRComparer::compare(Any IR, StringRef Prefix, StringRef PassID, 648 StringRef Name) { 649 if (!getModuleForComparison(IR)) { 650 // Not a module so just handle the single function. 651 assert(Before.getData().size() == 1 && "Expected only one function."); 652 assert(After.getData().size() == 1 && "Expected only one function."); 653 handleFunctionCompare(Name, Prefix, PassID, false, 654 Before.getData().begin()->getValue(), 655 After.getData().begin()->getValue()); 656 return; 657 } 658 659 ChangedIRData::report( 660 Before, After, [&](const ChangedFuncData *B, const ChangedFuncData *A) { 661 ChangedFuncData Missing; 662 if (!B) 663 B = &Missing; 664 else if (!A) 665 A = &Missing; 666 assert(B != &Missing && A != &Missing && 667 "Both functions cannot be missing."); 668 handleFunctionCompare(Name, Prefix, PassID, true, *B, *A); 669 }); 670 } 671 672 void ChangedIRComparer::analyzeIR(Any IR, ChangedIRData &Data) { 673 if (const Module *M = getModuleForComparison(IR)) { 674 // Create data for each existing/interesting function in the module. 675 for (const Function &F : *M) 676 generateFunctionData(Data, F); 677 return; 678 } 679 680 const Function *F = nullptr; 681 if (any_isa<const Function *>(IR)) 682 F = any_cast<const Function *>(IR); 683 else { 684 assert(any_isa<const Loop *>(IR) && "Unknown IR unit."); 685 const Loop *L = any_cast<const Loop *>(IR); 686 F = L->getHeader()->getParent(); 687 } 688 assert(F && "Unknown IR unit."); 689 generateFunctionData(Data, *F); 690 } 691 692 const Module *ChangedIRComparer::getModuleForComparison(Any IR) { 693 if (any_isa<const Module *>(IR)) 694 return any_cast<const Module *>(IR); 695 if (any_isa<const LazyCallGraph::SCC *>(IR)) 696 return any_cast<const LazyCallGraph::SCC *>(IR) 697 ->begin() 698 ->getFunction() 699 .getParent(); 700 return nullptr; 701 } 702 703 bool ChangedIRComparer::generateFunctionData(ChangedIRData &Data, 704 const Function &F) { 705 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 706 ChangedFuncData CFD; 707 for (const auto &B : F) { 708 CFD.getOrder().emplace_back(B.getName()); 709 CFD.getData().insert({B.getName(), B}); 710 } 711 Data.getOrder().emplace_back(F.getName()); 712 Data.getData().insert({F.getName(), CFD}); 713 return true; 714 } 715 return false; 716 } 717 718 PrintIRInstrumentation::~PrintIRInstrumentation() { 719 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit"); 720 } 721 722 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) { 723 assert(StoreModuleDesc); 724 const Module *M = unwrapModule(IR); 725 ModuleDescStack.emplace_back(M, getIRName(IR), PassID); 726 } 727 728 PrintIRInstrumentation::PrintModuleDesc 729 PrintIRInstrumentation::popModuleDesc(StringRef PassID) { 730 assert(!ModuleDescStack.empty() && "empty ModuleDescStack"); 731 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val(); 732 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack"); 733 return ModuleDesc; 734 } 735 736 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 737 if (isIgnored(PassID)) 738 return; 739 740 // Saving Module for AfterPassInvalidated operations. 741 // Note: here we rely on a fact that we do not change modules while 742 // traversing the pipeline, so the latest captured module is good 743 // for all print operations that has not happen yet. 744 if (StoreModuleDesc && shouldPrintAfterPass(PassID)) 745 pushModuleDesc(PassID, IR); 746 747 if (!shouldPrintBeforePass(PassID)) 748 return; 749 750 if (!shouldPrintIR(IR)) 751 return; 752 753 dbgs() << "*** IR Dump Before " << PassID << " on " << getIRName(IR) 754 << " ***\n"; 755 unwrapAndPrint(dbgs(), IR); 756 } 757 758 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 759 if (isIgnored(PassID)) 760 return; 761 762 if (!shouldPrintAfterPass(PassID)) 763 return; 764 765 if (StoreModuleDesc) { 766 const Module *M; 767 std::string IRName; 768 StringRef StoredPassID; 769 std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID); 770 assert(StoredPassID == PassID && "mismatched PassID"); 771 } 772 773 if (!shouldPrintIR(IR)) 774 return; 775 776 dbgs() << "*** IR Dump After " << PassID << " on " << getIRName(IR) 777 << " ***\n"; 778 unwrapAndPrint(dbgs(), IR); 779 } 780 781 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 782 StringRef PassName = PIC->getPassNameForClassName(PassID); 783 if (!StoreModuleDesc || !shouldPrintAfterPass(PassName)) 784 return; 785 786 if (isIgnored(PassID)) 787 return; 788 789 const Module *M; 790 std::string IRName; 791 StringRef StoredPassID; 792 std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID); 793 assert(StoredPassID == PassID && "mismatched PassID"); 794 // Additional filtering (e.g. -filter-print-func) can lead to module 795 // printing being skipped. 796 if (!M) 797 return; 798 799 SmallString<20> Banner = 800 formatv("*** IR Dump After {0} on {1} (invalidated) ***", PassID, IRName); 801 dbgs() << Banner << "\n"; 802 printIR(dbgs(), M); 803 } 804 805 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) { 806 if (shouldPrintBeforeAll()) 807 return true; 808 809 StringRef PassName = PIC->getPassNameForClassName(PassID); 810 return llvm::is_contained(printBeforePasses(), PassName); 811 } 812 813 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) { 814 if (shouldPrintAfterAll()) 815 return true; 816 817 StringRef PassName = PIC->getPassNameForClassName(PassID); 818 return llvm::is_contained(printAfterPasses(), PassName); 819 } 820 821 void PrintIRInstrumentation::registerCallbacks( 822 PassInstrumentationCallbacks &PIC) { 823 this->PIC = &PIC; 824 825 // BeforePass callback is not just for printing, it also saves a Module 826 // for later use in AfterPassInvalidated. 827 StoreModuleDesc = forcePrintModuleIR() && shouldPrintAfterSomePass(); 828 if (shouldPrintBeforeSomePass() || StoreModuleDesc) 829 PIC.registerBeforeNonSkippedPassCallback( 830 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 831 832 if (shouldPrintAfterSomePass()) { 833 PIC.registerAfterPassCallback( 834 [this](StringRef P, Any IR, const PreservedAnalyses &) { 835 this->printAfterPass(P, IR); 836 }); 837 PIC.registerAfterPassInvalidatedCallback( 838 [this](StringRef P, const PreservedAnalyses &) { 839 this->printAfterPassInvalidated(P); 840 }); 841 } 842 } 843 844 void OptNoneInstrumentation::registerCallbacks( 845 PassInstrumentationCallbacks &PIC) { 846 PIC.registerShouldRunOptionalPassCallback( 847 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); }); 848 } 849 850 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) { 851 const Function *F = nullptr; 852 if (any_isa<const Function *>(IR)) { 853 F = any_cast<const Function *>(IR); 854 } else if (any_isa<const Loop *>(IR)) { 855 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 856 } 857 bool ShouldRun = !(F && F->hasOptNone()); 858 if (!ShouldRun && DebugLogging) { 859 errs() << "Skipping pass " << PassID << " on " << F->getName() 860 << " due to optnone attribute\n"; 861 } 862 return ShouldRun; 863 } 864 865 void OptBisectInstrumentation::registerCallbacks( 866 PassInstrumentationCallbacks &PIC) { 867 if (!OptBisector->isEnabled()) 868 return; 869 PIC.registerShouldRunOptionalPassCallback([](StringRef PassID, Any IR) { 870 return isIgnored(PassID) || OptBisector->checkPass(PassID, getIRName(IR)); 871 }); 872 } 873 874 void PrintPassInstrumentation::registerCallbacks( 875 PassInstrumentationCallbacks &PIC) { 876 if (!DebugLogging) 877 return; 878 879 std::vector<StringRef> SpecialPasses = {"PassManager"}; 880 if (!DebugPMVerbose) 881 SpecialPasses.emplace_back("PassAdaptor"); 882 883 PIC.registerBeforeSkippedPassCallback( 884 [SpecialPasses](StringRef PassID, Any IR) { 885 assert(!isSpecialPass(PassID, SpecialPasses) && 886 "Unexpectedly skipping special pass"); 887 888 dbgs() << "Skipping pass: " << PassID << " on " << getIRName(IR) 889 << "\n"; 890 }); 891 892 PIC.registerBeforeNonSkippedPassCallback( 893 [SpecialPasses](StringRef PassID, Any IR) { 894 if (isSpecialPass(PassID, SpecialPasses)) 895 return; 896 897 dbgs() << "Running pass: " << PassID << " on " << getIRName(IR) << "\n"; 898 }); 899 900 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) { 901 dbgs() << "Running analysis: " << PassID << " on " << getIRName(IR) << "\n"; 902 }); 903 } 904 905 void PassStructurePrinter::printWithIdent(bool Expand, const Twine &Msg) { 906 if (!Msg.isTriviallyEmpty()) 907 dbgs().indent(Ident) << Msg << "\n"; 908 Ident = Expand ? Ident + 2 : Ident - 2; 909 assert(Ident >= 0); 910 } 911 912 void PassStructurePrinter::registerCallbacks( 913 PassInstrumentationCallbacks &PIC) { 914 if (!DebugPassStructure) 915 return; 916 917 PIC.registerBeforeNonSkippedPassCallback([this](StringRef PassID, Any IR) { 918 printWithIdent(true, PassID + " on " + getIRName(IR)); 919 }); 920 PIC.registerAfterPassCallback( 921 [this](StringRef PassID, Any IR, const PreservedAnalyses &) { 922 printWithIdent(false, Twine()); 923 }); 924 925 PIC.registerAfterPassInvalidatedCallback( 926 [this](StringRef PassID, const PreservedAnalyses &) { 927 printWithIdent(false, Twine()); 928 }); 929 930 PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) { 931 printWithIdent(true, PassID + " analysis on " + getIRName(IR)); 932 }); 933 PIC.registerAfterAnalysisCallback( 934 [this](StringRef PassID, Any IR) { printWithIdent(false, Twine()); }); 935 } 936 937 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F, 938 bool TrackBBLifetime) { 939 if (TrackBBLifetime) 940 BBGuards = DenseMap<intptr_t, BBGuard>(F->size()); 941 for (const auto &BB : *F) { 942 if (BBGuards) 943 BBGuards->try_emplace(intptr_t(&BB), &BB); 944 for (auto *Succ : successors(&BB)) { 945 Graph[&BB][Succ]++; 946 if (BBGuards) 947 BBGuards->try_emplace(intptr_t(Succ), Succ); 948 } 949 } 950 } 951 952 static void printBBName(raw_ostream &out, const BasicBlock *BB) { 953 if (BB->hasName()) { 954 out << BB->getName() << "<" << BB << ">"; 955 return; 956 } 957 958 if (!BB->getParent()) { 959 out << "unnamed_removed<" << BB << ">"; 960 return; 961 } 962 963 if (BB == &BB->getParent()->getEntryBlock()) { 964 out << "entry" 965 << "<" << BB << ">"; 966 return; 967 } 968 969 unsigned FuncOrderBlockNum = 0; 970 for (auto &FuncBB : *BB->getParent()) { 971 if (&FuncBB == BB) 972 break; 973 FuncOrderBlockNum++; 974 } 975 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">"; 976 } 977 978 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out, 979 const CFG &Before, 980 const CFG &After) { 981 assert(!After.isPoisoned()); 982 if (Before.isPoisoned()) { 983 out << "Some blocks were deleted\n"; 984 return; 985 } 986 987 // Find and print graph differences. 988 if (Before.Graph.size() != After.Graph.size()) 989 out << "Different number of non-leaf basic blocks: before=" 990 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n"; 991 992 for (auto &BB : Before.Graph) { 993 auto BA = After.Graph.find(BB.first); 994 if (BA == After.Graph.end()) { 995 out << "Non-leaf block "; 996 printBBName(out, BB.first); 997 out << " is removed (" << BB.second.size() << " successors)\n"; 998 } 999 } 1000 1001 for (auto &BA : After.Graph) { 1002 auto BB = Before.Graph.find(BA.first); 1003 if (BB == Before.Graph.end()) { 1004 out << "Non-leaf block "; 1005 printBBName(out, BA.first); 1006 out << " is added (" << BA.second.size() << " successors)\n"; 1007 continue; 1008 } 1009 1010 if (BB->second == BA.second) 1011 continue; 1012 1013 out << "Different successors of block "; 1014 printBBName(out, BA.first); 1015 out << " (unordered):\n"; 1016 out << "- before (" << BB->second.size() << "): "; 1017 for (auto &SuccB : BB->second) { 1018 printBBName(out, SuccB.first); 1019 if (SuccB.second != 1) 1020 out << "(" << SuccB.second << "), "; 1021 else 1022 out << ", "; 1023 } 1024 out << "\n"; 1025 out << "- after (" << BA.second.size() << "): "; 1026 for (auto &SuccA : BA.second) { 1027 printBBName(out, SuccA.first); 1028 if (SuccA.second != 1) 1029 out << "(" << SuccA.second << "), "; 1030 else 1031 out << ", "; 1032 } 1033 out << "\n"; 1034 } 1035 } 1036 1037 // PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check 1038 // passes, that reported they kept CFG analyses up-to-date, did not actually 1039 // change CFG. This check is done as follows. Before every functional pass in 1040 // BeforeNonSkippedPassCallback a CFG snapshot (an instance of 1041 // PreservedCFGCheckerInstrumentation::CFG) is requested from 1042 // FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the 1043 // functional pass finishes and reports that CFGAnalyses or AllAnalyses are 1044 // up-to-date then the cached result of PreservedCFGCheckerAnalysis (if 1045 // available) is checked to be equal to a freshly created CFG snapshot. 1046 struct PreservedCFGCheckerAnalysis 1047 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> { 1048 friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>; 1049 1050 static AnalysisKey Key; 1051 1052 public: 1053 /// Provide the result type for this analysis pass. 1054 using Result = PreservedCFGCheckerInstrumentation::CFG; 1055 1056 /// Run the analysis pass over a function and produce CFG. 1057 Result run(Function &F, FunctionAnalysisManager &FAM) { 1058 return Result(&F, /* TrackBBLifetime */ true); 1059 } 1060 }; 1061 1062 AnalysisKey PreservedCFGCheckerAnalysis::Key; 1063 1064 bool PreservedCFGCheckerInstrumentation::CFG::invalidate( 1065 Function &F, const PreservedAnalyses &PA, 1066 FunctionAnalysisManager::Invalidator &) { 1067 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>(); 1068 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() || 1069 PAC.preservedSet<CFGAnalyses>()); 1070 } 1071 1072 void PreservedCFGCheckerInstrumentation::registerCallbacks( 1073 PassInstrumentationCallbacks &PIC, FunctionAnalysisManager &FAM) { 1074 if (!VerifyPreservedCFG) 1075 return; 1076 1077 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); }); 1078 1079 auto checkCFG = [](StringRef Pass, StringRef FuncName, const CFG &GraphBefore, 1080 const CFG &GraphAfter) { 1081 if (GraphAfter == GraphBefore) 1082 return; 1083 1084 dbgs() << "Error: " << Pass 1085 << " does not invalidate CFG analyses but CFG changes detected in " 1086 "function @" 1087 << FuncName << ":\n"; 1088 CFG::printDiff(dbgs(), GraphBefore, GraphAfter); 1089 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass)); 1090 }; 1091 1092 PIC.registerBeforeNonSkippedPassCallback( 1093 [this, &FAM](StringRef P, Any IR) { 1094 assert(&PassStack.emplace_back(P)); 1095 (void)this; 1096 if (!any_isa<const Function *>(IR)) 1097 return; 1098 1099 const auto *F = any_cast<const Function *>(IR); 1100 // Make sure a fresh CFG snapshot is available before the pass. 1101 FAM.getResult<PreservedCFGCheckerAnalysis>(*const_cast<Function *>(F)); 1102 }); 1103 1104 PIC.registerAfterPassInvalidatedCallback( 1105 [this](StringRef P, const PreservedAnalyses &PassPA) { 1106 assert(PassStack.pop_back_val() == P && 1107 "Before and After callbacks must correspond"); 1108 (void)this; 1109 }); 1110 1111 PIC.registerAfterPassCallback([this, &FAM, 1112 checkCFG](StringRef P, Any IR, 1113 const PreservedAnalyses &PassPA) { 1114 assert(PassStack.pop_back_val() == P && 1115 "Before and After callbacks must correspond"); 1116 (void)this; 1117 1118 if (!any_isa<const Function *>(IR)) 1119 return; 1120 1121 if (!PassPA.allAnalysesInSetPreserved<CFGAnalyses>() && 1122 !PassPA.allAnalysesInSetPreserved<AllAnalysesOn<Function>>()) 1123 return; 1124 1125 const auto *F = any_cast<const Function *>(IR); 1126 if (auto *GraphBefore = FAM.getCachedResult<PreservedCFGCheckerAnalysis>( 1127 *const_cast<Function *>(F))) 1128 checkCFG(P, F->getName(), *GraphBefore, 1129 CFG(F, /* TrackBBLifetime */ false)); 1130 }); 1131 } 1132 1133 void VerifyInstrumentation::registerCallbacks( 1134 PassInstrumentationCallbacks &PIC) { 1135 PIC.registerAfterPassCallback( 1136 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { 1137 if (isIgnored(P) || P == "VerifierPass") 1138 return; 1139 if (any_isa<const Function *>(IR) || any_isa<const Loop *>(IR)) { 1140 const Function *F; 1141 if (any_isa<const Loop *>(IR)) 1142 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 1143 else 1144 F = any_cast<const Function *>(IR); 1145 if (DebugLogging) 1146 dbgs() << "Verifying function " << F->getName() << "\n"; 1147 1148 if (verifyFunction(*F)) 1149 report_fatal_error("Broken function found, compilation aborted!"); 1150 } else if (any_isa<const Module *>(IR) || 1151 any_isa<const LazyCallGraph::SCC *>(IR)) { 1152 const Module *M; 1153 if (any_isa<const LazyCallGraph::SCC *>(IR)) 1154 M = any_cast<const LazyCallGraph::SCC *>(IR) 1155 ->begin() 1156 ->getFunction() 1157 .getParent(); 1158 else 1159 M = any_cast<const Module *>(IR); 1160 if (DebugLogging) 1161 dbgs() << "Verifying module " << M->getName() << "\n"; 1162 1163 if (verifyModule(*M)) 1164 report_fatal_error("Broken module found, compilation aborted!"); 1165 } 1166 }); 1167 } 1168 1169 InLineChangePrinter::~InLineChangePrinter() {} 1170 1171 void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID, 1172 ChangedIRData &D) { 1173 ChangedIRComparer::analyzeIR(IR, D); 1174 } 1175 1176 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name, 1177 const ChangedIRData &Before, 1178 const ChangedIRData &After, Any IR) { 1179 SmallString<20> Banner = 1180 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name); 1181 Out << Banner; 1182 ChangedIRComparer(Out, Before, After, UseColour) 1183 .compare(IR, "", PassID, Name); 1184 Out << "\n"; 1185 } 1186 1187 bool InLineChangePrinter::same(const ChangedIRData &D1, 1188 const ChangedIRData &D2) { 1189 return D1 == D2; 1190 } 1191 1192 void ChangedIRComparer::handleFunctionCompare(StringRef Name, StringRef Prefix, 1193 StringRef PassID, bool InModule, 1194 const ChangedFuncData &Before, 1195 const ChangedFuncData &After) { 1196 // Print a banner when this is being shown in the context of a module 1197 if (InModule) 1198 Out << "\n*** IR for function " << Name << " ***\n"; 1199 1200 ChangedFuncData::report( 1201 Before, After, [&](const ChangedBlockData *B, const ChangedBlockData *A) { 1202 StringRef BStr = B ? B->getBody() : "\n"; 1203 StringRef AStr = A ? A->getBody() : "\n"; 1204 const std::string Removed = 1205 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n"; 1206 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n"; 1207 const std::string NoChange = " %l\n"; 1208 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange); 1209 }); 1210 } 1211 1212 void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { 1213 if (PrintChanged == ChangePrinter::PrintChangedDiffVerbose || 1214 PrintChanged == ChangePrinter::PrintChangedDiffQuiet || 1215 PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose || 1216 PrintChanged == ChangePrinter::PrintChangedColourDiffQuiet) 1217 TextChangeReporter<ChangedIRData>::registerRequiredCallbacks(PIC); 1218 } 1219 1220 StandardInstrumentations::StandardInstrumentations(bool DebugLogging, 1221 bool VerifyEach) 1222 : PrintPass(DebugLogging), OptNone(DebugLogging), 1223 PrintChangedIR(PrintChanged == ChangePrinter::PrintChangedVerbose), 1224 PrintChangedDiff( 1225 PrintChanged == ChangePrinter::PrintChangedDiffVerbose || 1226 PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose, 1227 PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose || 1228 PrintChanged == ChangePrinter::PrintChangedColourDiffQuiet), 1229 Verify(DebugLogging), VerifyEach(VerifyEach) {} 1230 1231 void StandardInstrumentations::registerCallbacks( 1232 PassInstrumentationCallbacks &PIC, FunctionAnalysisManager *FAM) { 1233 PrintIR.registerCallbacks(PIC); 1234 PrintPass.registerCallbacks(PIC); 1235 StructurePrinter.registerCallbacks(PIC); 1236 TimePasses.registerCallbacks(PIC); 1237 OptNone.registerCallbacks(PIC); 1238 OptBisect.registerCallbacks(PIC); 1239 if (FAM) 1240 PreservedCFGChecker.registerCallbacks(PIC, *FAM); 1241 PrintChangedIR.registerCallbacks(PIC); 1242 PseudoProbeVerification.registerCallbacks(PIC); 1243 if (VerifyEach) 1244 Verify.registerCallbacks(PIC); 1245 PrintChangedDiff.registerCallbacks(PIC); 1246 } 1247 1248 namespace llvm { 1249 1250 template class ChangeReporter<std::string>; 1251 template class TextChangeReporter<std::string>; 1252 1253 template class ChangeReporter<ChangedIRData>; 1254 template class TextChangeReporter<ChangedIRData>; 1255 1256 } // namespace llvm 1257