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