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