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 for (const auto &P : printBeforePasses()) { 786 if (PassName == P) 787 return true; 788 } 789 return false; 790 } 791 792 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) { 793 if (shouldPrintAfterAll()) 794 return true; 795 796 StringRef PassName = PIC->getPassNameForClassName(PassID); 797 for (const auto &P : printAfterPasses()) { 798 if (PassName == P) 799 return true; 800 } 801 return false; 802 } 803 804 void PrintIRInstrumentation::registerCallbacks( 805 PassInstrumentationCallbacks &PIC) { 806 this->PIC = &PIC; 807 808 // BeforePass callback is not just for printing, it also saves a Module 809 // for later use in AfterPassInvalidated. 810 StoreModuleDesc = forcePrintModuleIR() && shouldPrintAfterSomePass(); 811 if (shouldPrintBeforeSomePass() || StoreModuleDesc) 812 PIC.registerBeforeNonSkippedPassCallback( 813 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 814 815 if (shouldPrintAfterSomePass()) { 816 PIC.registerAfterPassCallback( 817 [this](StringRef P, Any IR, const PreservedAnalyses &) { 818 this->printAfterPass(P, IR); 819 }); 820 PIC.registerAfterPassInvalidatedCallback( 821 [this](StringRef P, const PreservedAnalyses &) { 822 this->printAfterPassInvalidated(P); 823 }); 824 } 825 } 826 827 void OptNoneInstrumentation::registerCallbacks( 828 PassInstrumentationCallbacks &PIC) { 829 PIC.registerShouldRunOptionalPassCallback( 830 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); }); 831 } 832 833 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) { 834 const Function *F = nullptr; 835 if (any_isa<const Function *>(IR)) { 836 F = any_cast<const Function *>(IR); 837 } else if (any_isa<const Loop *>(IR)) { 838 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 839 } 840 bool ShouldRun = !(F && F->hasOptNone()); 841 if (!ShouldRun && DebugLogging) { 842 errs() << "Skipping pass " << PassID << " on " << F->getName() 843 << " due to optnone attribute\n"; 844 } 845 return ShouldRun; 846 } 847 848 static std::string getBisectDescription(Any IR) { 849 if (any_isa<const Module *>(IR)) { 850 const Module *M = any_cast<const Module *>(IR); 851 assert(M && "module should be valid for printing"); 852 return "module (" + M->getName().str() + ")"; 853 } 854 855 if (any_isa<const Function *>(IR)) { 856 const Function *F = any_cast<const Function *>(IR); 857 assert(F && "function should be valid for printing"); 858 return "function (" + F->getName().str() + ")"; 859 } 860 861 if (any_isa<const LazyCallGraph::SCC *>(IR)) { 862 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR); 863 assert(C && "scc should be valid for printing"); 864 return "SCC " + C->getName(); 865 } 866 867 if (any_isa<const Loop *>(IR)) { 868 return "loop"; 869 } 870 871 llvm_unreachable("Unknown wrapped IR type"); 872 } 873 874 void OptBisectInstrumentation::registerCallbacks( 875 PassInstrumentationCallbacks &PIC) { 876 if (!OptBisector->isEnabled()) 877 return; 878 PIC.registerShouldRunOptionalPassCallback([](StringRef PassID, Any IR) { 879 return isIgnored(PassID) || 880 OptBisector->checkPass(PassID, getBisectDescription(IR)); 881 }); 882 } 883 884 void PrintPassInstrumentation::registerCallbacks( 885 PassInstrumentationCallbacks &PIC) { 886 if (!DebugLogging) 887 return; 888 889 std::vector<StringRef> SpecialPasses = {"PassManager"}; 890 if (!DebugPMVerbose) 891 SpecialPasses.emplace_back("PassAdaptor"); 892 893 PIC.registerBeforeSkippedPassCallback( 894 [SpecialPasses](StringRef PassID, Any IR) { 895 assert(!isSpecialPass(PassID, SpecialPasses) && 896 "Unexpectedly skipping special pass"); 897 898 dbgs() << "Skipping pass: " << PassID << " on "; 899 unwrapAndPrint(dbgs(), IR, "", false, true); 900 }); 901 902 PIC.registerBeforeNonSkippedPassCallback( 903 [SpecialPasses](StringRef PassID, Any IR) { 904 if (isSpecialPass(PassID, SpecialPasses)) 905 return; 906 907 dbgs() << "Running pass: " << PassID << " on "; 908 unwrapAndPrint(dbgs(), IR, "", false, true); 909 }); 910 911 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) { 912 dbgs() << "Running analysis: " << PassID << " on "; 913 unwrapAndPrint(dbgs(), IR, "", false, true); 914 }); 915 } 916 917 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F, 918 bool TrackBBLifetime) { 919 if (TrackBBLifetime) 920 BBGuards = DenseMap<intptr_t, BBGuard>(F->size()); 921 for (const auto &BB : *F) { 922 if (BBGuards) 923 BBGuards->try_emplace(intptr_t(&BB), &BB); 924 for (auto *Succ : successors(&BB)) { 925 Graph[&BB][Succ]++; 926 if (BBGuards) 927 BBGuards->try_emplace(intptr_t(Succ), Succ); 928 } 929 } 930 } 931 932 static void printBBName(raw_ostream &out, const BasicBlock *BB) { 933 if (BB->hasName()) { 934 out << BB->getName() << "<" << BB << ">"; 935 return; 936 } 937 938 if (!BB->getParent()) { 939 out << "unnamed_removed<" << BB << ">"; 940 return; 941 } 942 943 if (BB == &BB->getParent()->getEntryBlock()) { 944 out << "entry" 945 << "<" << BB << ">"; 946 return; 947 } 948 949 unsigned FuncOrderBlockNum = 0; 950 for (auto &FuncBB : *BB->getParent()) { 951 if (&FuncBB == BB) 952 break; 953 FuncOrderBlockNum++; 954 } 955 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">"; 956 } 957 958 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out, 959 const CFG &Before, 960 const CFG &After) { 961 assert(!After.isPoisoned()); 962 963 // Print function name. 964 const CFG *FuncGraph = nullptr; 965 if (!After.Graph.empty()) 966 FuncGraph = &After; 967 else if (!Before.isPoisoned() && !Before.Graph.empty()) 968 FuncGraph = &Before; 969 970 if (FuncGraph) 971 out << "In function @" 972 << FuncGraph->Graph.begin()->first->getParent()->getName() << "\n"; 973 974 if (Before.isPoisoned()) { 975 out << "Some blocks were deleted\n"; 976 return; 977 } 978 979 // Find and print graph differences. 980 if (Before.Graph.size() != After.Graph.size()) 981 out << "Different number of non-leaf basic blocks: before=" 982 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n"; 983 984 for (auto &BB : Before.Graph) { 985 auto BA = After.Graph.find(BB.first); 986 if (BA == After.Graph.end()) { 987 out << "Non-leaf block "; 988 printBBName(out, BB.first); 989 out << " is removed (" << BB.second.size() << " successors)\n"; 990 } 991 } 992 993 for (auto &BA : After.Graph) { 994 auto BB = Before.Graph.find(BA.first); 995 if (BB == Before.Graph.end()) { 996 out << "Non-leaf block "; 997 printBBName(out, BA.first); 998 out << " is added (" << BA.second.size() << " successors)\n"; 999 continue; 1000 } 1001 1002 if (BB->second == BA.second) 1003 continue; 1004 1005 out << "Different successors of block "; 1006 printBBName(out, BA.first); 1007 out << " (unordered):\n"; 1008 out << "- before (" << BB->second.size() << "): "; 1009 for (auto &SuccB : BB->second) { 1010 printBBName(out, SuccB.first); 1011 if (SuccB.second != 1) 1012 out << "(" << SuccB.second << "), "; 1013 else 1014 out << ", "; 1015 } 1016 out << "\n"; 1017 out << "- after (" << BA.second.size() << "): "; 1018 for (auto &SuccA : BA.second) { 1019 printBBName(out, SuccA.first); 1020 if (SuccA.second != 1) 1021 out << "(" << SuccA.second << "), "; 1022 else 1023 out << ", "; 1024 } 1025 out << "\n"; 1026 } 1027 } 1028 1029 void PreservedCFGCheckerInstrumentation::registerCallbacks( 1030 PassInstrumentationCallbacks &PIC) { 1031 if (!VerifyPreservedCFG) 1032 return; 1033 1034 PIC.registerBeforeNonSkippedPassCallback([this](StringRef P, Any IR) { 1035 if (any_isa<const Function *>(IR)) 1036 GraphStackBefore.emplace_back(P, CFG(any_cast<const Function *>(IR))); 1037 else 1038 GraphStackBefore.emplace_back(P, None); 1039 }); 1040 1041 PIC.registerAfterPassInvalidatedCallback( 1042 [this](StringRef P, const PreservedAnalyses &PassPA) { 1043 auto Before = GraphStackBefore.pop_back_val(); 1044 assert(Before.first == P && 1045 "Before and After callbacks must correspond"); 1046 (void)Before; 1047 }); 1048 1049 PIC.registerAfterPassCallback([this](StringRef P, Any IR, 1050 const PreservedAnalyses &PassPA) { 1051 auto Before = GraphStackBefore.pop_back_val(); 1052 assert(Before.first == P && "Before and After callbacks must correspond"); 1053 auto &GraphBefore = Before.second; 1054 1055 if (!PassPA.allAnalysesInSetPreserved<CFGAnalyses>()) 1056 return; 1057 1058 if (any_isa<const Function *>(IR)) { 1059 assert(GraphBefore && "Must be built in BeforePassCallback"); 1060 CFG GraphAfter(any_cast<const Function *>(IR), false /* NeedsGuard */); 1061 if (GraphAfter == *GraphBefore) 1062 return; 1063 1064 dbgs() << "Error: " << P 1065 << " reported it preserved CFG, but changes detected:\n"; 1066 CFG::printDiff(dbgs(), *GraphBefore, GraphAfter); 1067 report_fatal_error(Twine("Preserved CFG changed by ", P)); 1068 } 1069 }); 1070 } 1071 1072 void VerifyInstrumentation::registerCallbacks( 1073 PassInstrumentationCallbacks &PIC) { 1074 PIC.registerAfterPassCallback( 1075 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { 1076 if (isIgnored(P) || P == "VerifierPass") 1077 return; 1078 if (any_isa<const Function *>(IR) || any_isa<const Loop *>(IR)) { 1079 const Function *F; 1080 if (any_isa<const Loop *>(IR)) 1081 F = any_cast<const Loop *>(IR)->getHeader()->getParent(); 1082 else 1083 F = any_cast<const Function *>(IR); 1084 if (DebugLogging) 1085 dbgs() << "Verifying function " << F->getName() << "\n"; 1086 1087 if (verifyFunction(*F)) 1088 report_fatal_error("Broken function found, compilation aborted!"); 1089 } else if (any_isa<const Module *>(IR) || 1090 any_isa<const LazyCallGraph::SCC *>(IR)) { 1091 const Module *M; 1092 if (any_isa<const LazyCallGraph::SCC *>(IR)) 1093 M = any_cast<const LazyCallGraph::SCC *>(IR) 1094 ->begin() 1095 ->getFunction() 1096 .getParent(); 1097 else 1098 M = any_cast<const Module *>(IR); 1099 if (DebugLogging) 1100 dbgs() << "Verifying module " << M->getName() << "\n"; 1101 1102 if (verifyModule(*M)) 1103 report_fatal_error("Broken module found, compilation aborted!"); 1104 } 1105 }); 1106 } 1107 1108 InLineChangePrinter::~InLineChangePrinter() {} 1109 1110 void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID, 1111 ChangedIRData &D) { 1112 ChangedIRComparer::analyzeIR(IR, D); 1113 } 1114 1115 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name, 1116 const ChangedIRData &Before, 1117 const ChangedIRData &After, Any IR) { 1118 if (Name == "") 1119 Name = " (module)"; 1120 SmallString<20> Banner = 1121 formatv("*** IR Dump After {0} ***{1}\n", PassID, Name); 1122 Out << Banner; 1123 ChangedIRComparer(Out, Before, After).compare(IR, "", PassID, Name); 1124 Out << "\n"; 1125 } 1126 1127 bool InLineChangePrinter::same(const ChangedIRData &D1, 1128 const ChangedIRData &D2) { 1129 return D1 == D2; 1130 } 1131 1132 void ChangedIRComparer::handleFunctionCompare(StringRef Name, StringRef Prefix, 1133 StringRef PassID, bool InModule, 1134 const ChangedFuncData &Before, 1135 const ChangedFuncData &After) { 1136 // Print a banner when this is being shown in the context of a module 1137 if (InModule) 1138 Out << "\n*** IR for function " << Name << " ***\n"; 1139 1140 ChangedFuncData::report( 1141 Before, After, [&](const ChangedBlockData *B, const ChangedBlockData *A) { 1142 StringRef BStr = B ? B->getBody() : "\n"; 1143 StringRef AStr = A ? A->getBody() : "\n"; 1144 const std::string Removed = "\033[31m-%l\033[0m\n"; 1145 const std::string Added = "\033[32m+%l\033[0m\n"; 1146 const std::string NoChange = " %l\n"; 1147 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange); 1148 }); 1149 } 1150 1151 void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { 1152 if (PrintChanged == ChangePrinter::PrintChangedDiffVerbose || 1153 PrintChanged == ChangePrinter::PrintChangedDiffQuiet) 1154 TextChangeReporter<ChangedIRData>::registerRequiredCallbacks(PIC); 1155 } 1156 1157 StandardInstrumentations::StandardInstrumentations(bool DebugLogging, 1158 bool VerifyEach) 1159 : PrintPass(DebugLogging), OptNone(DebugLogging), 1160 PrintChangedIR(PrintChanged == ChangePrinter::PrintChangedVerbose), 1161 PrintChangedDiff(PrintChanged == ChangePrinter::PrintChangedDiffVerbose), 1162 Verify(DebugLogging), VerifyEach(VerifyEach) {} 1163 1164 void StandardInstrumentations::registerCallbacks( 1165 PassInstrumentationCallbacks &PIC) { 1166 PrintIR.registerCallbacks(PIC); 1167 PrintPass.registerCallbacks(PIC); 1168 TimePasses.registerCallbacks(PIC); 1169 OptNone.registerCallbacks(PIC); 1170 OptBisect.registerCallbacks(PIC); 1171 PreservedCFGChecker.registerCallbacks(PIC); 1172 PrintChangedIR.registerCallbacks(PIC); 1173 PseudoProbeVerification.registerCallbacks(PIC); 1174 if (VerifyEach) 1175 Verify.registerCallbacks(PIC); 1176 PrintChangedDiff.registerCallbacks(PIC); 1177 } 1178 1179 namespace llvm { 1180 1181 template class ChangeReporter<std::string>; 1182 template class TextChangeReporter<std::string>; 1183 1184 template class ChangeReporter<ChangedIRData>; 1185 template class TextChangeReporter<ChangedIRData>; 1186 1187 } // namespace llvm 1188