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/StableHashing.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/CodeGen/MachineFunction.h" 23 #include "llvm/IR/Constants.h" 24 #include "llvm/IR/Function.h" 25 #include "llvm/IR/Module.h" 26 #include "llvm/IR/PassInstrumentation.h" 27 #include "llvm/IR/PassManager.h" 28 #include "llvm/IR/PrintPasses.h" 29 #include "llvm/IR/StructuralHash.h" 30 #include "llvm/IR/Verifier.h" 31 #include "llvm/Support/CommandLine.h" 32 #include "llvm/Support/CrashRecoveryContext.h" 33 #include "llvm/Support/Debug.h" 34 #include "llvm/Support/Error.h" 35 #include "llvm/Support/FormatVariadic.h" 36 #include "llvm/Support/GraphWriter.h" 37 #include "llvm/Support/MemoryBuffer.h" 38 #include "llvm/Support/Path.h" 39 #include "llvm/Support/Program.h" 40 #include "llvm/Support/Regex.h" 41 #include "llvm/Support/Signals.h" 42 #include "llvm/Support/raw_ostream.h" 43 #include <unordered_map> 44 #include <unordered_set> 45 #include <utility> 46 #include <vector> 47 48 using namespace llvm; 49 50 static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation", 51 cl::Hidden, 52 #ifdef EXPENSIVE_CHECKS 53 cl::init(true) 54 #else 55 cl::init(false) 56 #endif 57 ); 58 59 // An option that supports the -print-changed option. See 60 // the description for -print-changed for an explanation of the use 61 // of this option. Note that this option has no effect without -print-changed. 62 static cl::opt<bool> 63 PrintChangedBefore("print-before-changed", 64 cl::desc("Print before passes that change them"), 65 cl::init(false), cl::Hidden); 66 67 // An option for specifying the dot used by 68 // print-changed=[dot-cfg | dot-cfg-quiet] 69 static cl::opt<std::string> 70 DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"), 71 cl::desc("system dot used by change reporters")); 72 73 // An option that determines the colour used for elements that are only 74 // in the before part. Must be a colour named in appendix J of 75 // https://graphviz.org/pdf/dotguide.pdf 76 static cl::opt<std::string> 77 BeforeColour("dot-cfg-before-color", 78 cl::desc("Color for dot-cfg before elements"), cl::Hidden, 79 cl::init("red")); 80 // An option that determines the colour used for elements that are only 81 // in the after part. Must be a colour named in appendix J of 82 // https://graphviz.org/pdf/dotguide.pdf 83 static cl::opt<std::string> 84 AfterColour("dot-cfg-after-color", 85 cl::desc("Color for dot-cfg after elements"), cl::Hidden, 86 cl::init("forestgreen")); 87 // An option that determines the colour used for elements that are in both 88 // the before and after parts. Must be a colour named in appendix J of 89 // https://graphviz.org/pdf/dotguide.pdf 90 static cl::opt<std::string> 91 CommonColour("dot-cfg-common-color", 92 cl::desc("Color for dot-cfg common elements"), cl::Hidden, 93 cl::init("black")); 94 95 // An option that determines where the generated website file (named 96 // passes.html) and the associated pdf files (named diff_*.pdf) are saved. 97 static cl::opt<std::string> DotCfgDir( 98 "dot-cfg-dir", 99 cl::desc("Generate dot files into specified directory for changed IRs"), 100 cl::Hidden, cl::init("./")); 101 102 // Options to print the IR that was being processed when a pass crashes. 103 static cl::opt<std::string> PrintOnCrashPath( 104 "print-on-crash-path", 105 cl::desc("Print the last form of the IR before crash to a file"), 106 cl::Hidden); 107 108 static cl::opt<bool> PrintOnCrash( 109 "print-on-crash", 110 cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"), 111 cl::Hidden); 112 113 static cl::opt<std::string> OptBisectPrintIRPath( 114 "opt-bisect-print-ir-path", 115 cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden); 116 117 static cl::opt<bool> PrintPassNumbers( 118 "print-pass-numbers", cl::init(false), cl::Hidden, 119 cl::desc("Print pass names and their ordinals")); 120 121 static cl::opt<unsigned> PrintBeforePassNumber( 122 "print-before-pass-number", cl::init(0), cl::Hidden, 123 cl::desc("Print IR before the pass with this number as " 124 "reported by print-pass-numbers")); 125 126 static cl::opt<std::string> IRDumpDirectory( 127 "ir-dump-directory", 128 cl::desc("If specified, IR printed using the " 129 "-print-[before|after]{-all} options will be dumped into " 130 "files in this directory rather than written to stderr"), 131 cl::Hidden, cl::value_desc("filename")); 132 133 template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) { 134 const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR); 135 return IRPtr ? *IRPtr : nullptr; 136 } 137 138 namespace { 139 140 // An option for specifying an executable that will be called with the IR 141 // everytime it changes in the opt pipeline. It will also be called on 142 // the initial IR as it enters the pipeline. The executable will be passed 143 // the name of a temporary file containing the IR and the PassID. This may 144 // be used, for example, to call llc on the IR and run a test to determine 145 // which pass makes a change that changes the functioning of the IR. 146 // The usual modifier options work as expected. 147 static cl::opt<std::string> 148 TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""), 149 cl::desc("exe called with module IR after each pass that " 150 "changes it")); 151 152 /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match 153 /// certain global filters. Will never return nullptr if \p Force is true. 154 const Module *unwrapModule(Any IR, bool Force = false) { 155 if (const auto *M = unwrapIR<Module>(IR)) 156 return M; 157 158 if (const auto *F = unwrapIR<Function>(IR)) { 159 if (!Force && !isFunctionInPrintList(F->getName())) 160 return nullptr; 161 162 return F->getParent(); 163 } 164 165 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) { 166 for (const LazyCallGraph::Node &N : *C) { 167 const Function &F = N.getFunction(); 168 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) { 169 return F.getParent(); 170 } 171 } 172 assert(!Force && "Expected a module"); 173 return nullptr; 174 } 175 176 if (const auto *L = unwrapIR<Loop>(IR)) { 177 const Function *F = L->getHeader()->getParent(); 178 if (!Force && !isFunctionInPrintList(F->getName())) 179 return nullptr; 180 return F->getParent(); 181 } 182 183 llvm_unreachable("Unknown IR unit"); 184 } 185 186 void printIR(raw_ostream &OS, const Function *F) { 187 if (!isFunctionInPrintList(F->getName())) 188 return; 189 OS << *F; 190 } 191 192 void printIR(raw_ostream &OS, const Module *M) { 193 if (isFunctionInPrintList("*") || forcePrintModuleIR()) { 194 M->print(OS, nullptr); 195 } else { 196 for (const auto &F : M->functions()) { 197 printIR(OS, &F); 198 } 199 } 200 } 201 202 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) { 203 for (const LazyCallGraph::Node &N : *C) { 204 const Function &F = N.getFunction(); 205 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 206 F.print(OS); 207 } 208 } 209 } 210 211 void printIR(raw_ostream &OS, const Loop *L) { 212 const Function *F = L->getHeader()->getParent(); 213 if (!isFunctionInPrintList(F->getName())) 214 return; 215 printLoop(const_cast<Loop &>(*L), OS); 216 } 217 218 std::string getIRName(Any IR) { 219 if (unwrapIR<Module>(IR)) 220 return "[module]"; 221 222 if (const auto *F = unwrapIR<Function>(IR)) 223 return F->getName().str(); 224 225 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) 226 return C->getName(); 227 228 if (const auto *L = unwrapIR<Loop>(IR)) 229 return L->getName().str(); 230 231 if (const auto *MF = unwrapIR<MachineFunction>(IR)) 232 return MF->getName().str(); 233 234 llvm_unreachable("Unknown wrapped IR type"); 235 } 236 237 bool moduleContainsFilterPrintFunc(const Module &M) { 238 return any_of(M.functions(), 239 [](const Function &F) { 240 return isFunctionInPrintList(F.getName()); 241 }) || 242 isFunctionInPrintList("*"); 243 } 244 245 bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) { 246 return any_of(C, 247 [](const LazyCallGraph::Node &N) { 248 return isFunctionInPrintList(N.getName()); 249 }) || 250 isFunctionInPrintList("*"); 251 } 252 253 bool shouldPrintIR(Any IR) { 254 if (const auto *M = unwrapIR<Module>(IR)) 255 return moduleContainsFilterPrintFunc(*M); 256 257 if (const auto *F = unwrapIR<Function>(IR)) 258 return isFunctionInPrintList(F->getName()); 259 260 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) 261 return sccContainsFilterPrintFunc(*C); 262 263 if (const auto *L = unwrapIR<Loop>(IR)) 264 return isFunctionInPrintList(L->getHeader()->getParent()->getName()); 265 llvm_unreachable("Unknown wrapped IR type"); 266 } 267 268 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into 269 /// Any and does actual print job. 270 void unwrapAndPrint(raw_ostream &OS, Any IR) { 271 if (!shouldPrintIR(IR)) 272 return; 273 274 if (forcePrintModuleIR()) { 275 auto *M = unwrapModule(IR); 276 assert(M && "should have unwrapped module"); 277 printIR(OS, M); 278 return; 279 } 280 281 if (const auto *M = unwrapIR<Module>(IR)) { 282 printIR(OS, M); 283 return; 284 } 285 286 if (const auto *F = unwrapIR<Function>(IR)) { 287 printIR(OS, F); 288 return; 289 } 290 291 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) { 292 printIR(OS, C); 293 return; 294 } 295 296 if (const auto *L = unwrapIR<Loop>(IR)) { 297 printIR(OS, L); 298 return; 299 } 300 llvm_unreachable("Unknown wrapped IR type"); 301 } 302 303 // Return true when this is a pass for which changes should be ignored 304 bool isIgnored(StringRef PassID) { 305 return isSpecialPass(PassID, 306 {"PassManager", "PassAdaptor", "AnalysisManagerProxy", 307 "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass", 308 "VerifierPass", "PrintModulePass"}); 309 } 310 311 std::string makeHTMLReady(StringRef SR) { 312 std::string S; 313 while (true) { 314 StringRef Clean = 315 SR.take_until([](char C) { return C == '<' || C == '>'; }); 316 S.append(Clean.str()); 317 SR = SR.drop_front(Clean.size()); 318 if (SR.size() == 0) 319 return S; 320 S.append(SR[0] == '<' ? "<" : ">"); 321 SR = SR.drop_front(); 322 } 323 llvm_unreachable("problems converting string to HTML"); 324 } 325 326 // Return the module when that is the appropriate level of comparison for \p IR. 327 const Module *getModuleForComparison(Any IR) { 328 if (const auto *M = unwrapIR<Module>(IR)) 329 return M; 330 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) 331 return C->begin()->getFunction().getParent(); 332 return nullptr; 333 } 334 335 bool isInterestingFunction(const Function &F) { 336 return isFunctionInPrintList(F.getName()); 337 } 338 339 // Return true when this is a pass on IR for which printing 340 // of changes is desired. 341 bool isInteresting(Any IR, StringRef PassID, StringRef PassName) { 342 if (isIgnored(PassID) || !isPassInPrintList(PassName)) 343 return false; 344 if (const auto *F = unwrapIR<Function>(IR)) 345 return isInterestingFunction(*F); 346 return true; 347 } 348 349 } // namespace 350 351 template <typename T> ChangeReporter<T>::~ChangeReporter() { 352 assert(BeforeStack.empty() && "Problem with Change Printer stack."); 353 } 354 355 template <typename T> 356 void ChangeReporter<T>::saveIRBeforePass(Any IR, StringRef PassID, 357 StringRef PassName) { 358 // Is this the initial IR? 359 if (InitialIR) { 360 InitialIR = false; 361 if (VerboseMode) 362 handleInitialIR(IR); 363 } 364 365 // Always need to place something on the stack because invalidated passes 366 // are not given the IR so it cannot be determined whether the pass was for 367 // something that was filtered out. 368 BeforeStack.emplace_back(); 369 370 if (!isInteresting(IR, PassID, PassName)) 371 return; 372 373 // Save the IR representation on the stack. 374 T &Data = BeforeStack.back(); 375 generateIRRepresentation(IR, PassID, Data); 376 } 377 378 template <typename T> 379 void ChangeReporter<T>::handleIRAfterPass(Any IR, StringRef PassID, 380 StringRef PassName) { 381 assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); 382 383 std::string Name = getIRName(IR); 384 385 if (isIgnored(PassID)) { 386 if (VerboseMode) 387 handleIgnored(PassID, Name); 388 } else if (!isInteresting(IR, PassID, PassName)) { 389 if (VerboseMode) 390 handleFiltered(PassID, Name); 391 } else { 392 // Get the before rep from the stack 393 T &Before = BeforeStack.back(); 394 // Create the after rep 395 T After; 396 generateIRRepresentation(IR, PassID, After); 397 398 // Was there a change in IR? 399 if (Before == After) { 400 if (VerboseMode) 401 omitAfter(PassID, Name); 402 } else 403 handleAfter(PassID, Name, Before, After, IR); 404 } 405 BeforeStack.pop_back(); 406 } 407 408 template <typename T> 409 void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) { 410 assert(!BeforeStack.empty() && "Unexpected empty stack encountered."); 411 412 // Always flag it as invalidated as we cannot determine when 413 // a pass for a filtered function is invalidated since we do not 414 // get the IR in the call. Also, the output is just alternate 415 // forms of the banner anyway. 416 if (VerboseMode) 417 handleInvalidated(PassID); 418 BeforeStack.pop_back(); 419 } 420 421 template <typename T> 422 void ChangeReporter<T>::registerRequiredCallbacks( 423 PassInstrumentationCallbacks &PIC) { 424 PIC.registerBeforeNonSkippedPassCallback([&PIC, this](StringRef P, Any IR) { 425 saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P)); 426 }); 427 428 PIC.registerAfterPassCallback( 429 [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) { 430 handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P)); 431 }); 432 PIC.registerAfterPassInvalidatedCallback( 433 [this](StringRef P, const PreservedAnalyses &) { 434 handleInvalidatedPass(P); 435 }); 436 } 437 438 template <typename T> 439 TextChangeReporter<T>::TextChangeReporter(bool Verbose) 440 : ChangeReporter<T>(Verbose), Out(dbgs()) {} 441 442 template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) { 443 // Always print the module. 444 // Unwrap and print directly to avoid filtering problems in general routines. 445 auto *M = unwrapModule(IR, /*Force=*/true); 446 assert(M && "Expected module to be unwrapped when forced."); 447 Out << "*** IR Dump At Start ***\n"; 448 M->print(Out, nullptr); 449 } 450 451 template <typename T> 452 void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) { 453 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n", 454 PassID, Name); 455 } 456 457 template <typename T> 458 void TextChangeReporter<T>::handleInvalidated(StringRef PassID) { 459 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID); 460 } 461 462 template <typename T> 463 void TextChangeReporter<T>::handleFiltered(StringRef PassID, 464 std::string &Name) { 465 SmallString<20> Banner = 466 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name); 467 Out << Banner; 468 } 469 470 template <typename T> 471 void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) { 472 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name); 473 } 474 475 IRChangedPrinter::~IRChangedPrinter() = default; 476 477 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { 478 if (PrintChanged == ChangePrinter::Verbose || 479 PrintChanged == ChangePrinter::Quiet) 480 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC); 481 } 482 483 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID, 484 std::string &Output) { 485 raw_string_ostream OS(Output); 486 unwrapAndPrint(OS, IR); 487 OS.str(); 488 } 489 490 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name, 491 const std::string &Before, 492 const std::string &After, Any) { 493 // Report the IR before the changes when requested. 494 if (PrintChangedBefore) 495 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n" 496 << Before; 497 498 // We might not get anything to print if we only want to print a specific 499 // function but it gets deleted. 500 if (After.empty()) { 501 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n"; 502 return; 503 } 504 505 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After; 506 } 507 508 IRChangedTester::~IRChangedTester() {} 509 510 void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) { 511 if (TestChanged != "") 512 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC); 513 } 514 515 void IRChangedTester::handleIR(const std::string &S, StringRef PassID) { 516 // Store the body into a temporary file 517 static SmallVector<int> FD{-1}; 518 SmallVector<StringRef> SR{S}; 519 static SmallVector<std::string> FileName{""}; 520 if (prepareTempFiles(FD, SR, FileName)) { 521 dbgs() << "Unable to create temporary file."; 522 return; 523 } 524 static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged); 525 if (!Exe) { 526 dbgs() << "Unable to find test-changed executable."; 527 return; 528 } 529 530 StringRef Args[] = {TestChanged, FileName[0], PassID}; 531 int Result = sys::ExecuteAndWait(*Exe, Args); 532 if (Result < 0) { 533 dbgs() << "Error executing test-changed executable."; 534 return; 535 } 536 537 if (cleanUpTempFiles(FileName)) 538 dbgs() << "Unable to remove temporary file."; 539 } 540 541 void IRChangedTester::handleInitialIR(Any IR) { 542 // Always test the initial module. 543 // Unwrap and print directly to avoid filtering problems in general routines. 544 std::string S; 545 generateIRRepresentation(IR, "Initial IR", S); 546 handleIR(S, "Initial IR"); 547 } 548 549 void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {} 550 void IRChangedTester::handleInvalidated(StringRef PassID) {} 551 void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {} 552 void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {} 553 void IRChangedTester::handleAfter(StringRef PassID, std::string &Name, 554 const std::string &Before, 555 const std::string &After, Any) { 556 handleIR(After, PassID); 557 } 558 559 template <typename T> 560 void OrderedChangedData<T>::report( 561 const OrderedChangedData &Before, const OrderedChangedData &After, 562 function_ref<void(const T *, const T *)> HandlePair) { 563 const auto &BFD = Before.getData(); 564 const auto &AFD = After.getData(); 565 std::vector<std::string>::const_iterator BI = Before.getOrder().begin(); 566 std::vector<std::string>::const_iterator BE = Before.getOrder().end(); 567 std::vector<std::string>::const_iterator AI = After.getOrder().begin(); 568 std::vector<std::string>::const_iterator AE = After.getOrder().end(); 569 570 auto HandlePotentiallyRemovedData = [&](std::string S) { 571 // The order in LLVM may have changed so check if still exists. 572 if (!AFD.count(S)) { 573 // This has been removed. 574 HandlePair(&BFD.find(*BI)->getValue(), nullptr); 575 } 576 }; 577 auto HandleNewData = [&](std::vector<const T *> &Q) { 578 // Print out any queued up new sections 579 for (const T *NBI : Q) 580 HandlePair(nullptr, NBI); 581 Q.clear(); 582 }; 583 584 // Print out the data in the after order, with before ones interspersed 585 // appropriately (ie, somewhere near where they were in the before list). 586 // Start at the beginning of both lists. Loop through the 587 // after list. If an element is common, then advance in the before list 588 // reporting the removed ones until the common one is reached. Report any 589 // queued up new ones and then report the common one. If an element is not 590 // common, then enqueue it for reporting. When the after list is exhausted, 591 // loop through the before list, reporting any removed ones. Finally, 592 // report the rest of the enqueued new ones. 593 std::vector<const T *> NewDataQueue; 594 while (AI != AE) { 595 if (!BFD.count(*AI)) { 596 // This section is new so place it in the queue. This will cause it 597 // to be reported after deleted sections. 598 NewDataQueue.emplace_back(&AFD.find(*AI)->getValue()); 599 ++AI; 600 continue; 601 } 602 // This section is in both; advance and print out any before-only 603 // until we get to it. 604 // It's possible that this section has moved to be later than before. This 605 // will mess up printing most blocks side by side, but it's a rare case and 606 // it's better than crashing. 607 while (BI != BE && *BI != *AI) { 608 HandlePotentiallyRemovedData(*BI); 609 ++BI; 610 } 611 // Report any new sections that were queued up and waiting. 612 HandleNewData(NewDataQueue); 613 614 const T &AData = AFD.find(*AI)->getValue(); 615 const T &BData = BFD.find(*AI)->getValue(); 616 HandlePair(&BData, &AData); 617 if (BI != BE) 618 ++BI; 619 ++AI; 620 } 621 622 // Check any remaining before sections to see if they have been removed 623 while (BI != BE) { 624 HandlePotentiallyRemovedData(*BI); 625 ++BI; 626 } 627 628 HandleNewData(NewDataQueue); 629 } 630 631 template <typename T> 632 void IRComparer<T>::compare( 633 bool CompareModule, 634 std::function<void(bool InModule, unsigned Minor, 635 const FuncDataT<T> &Before, const FuncDataT<T> &After)> 636 CompareFunc) { 637 if (!CompareModule) { 638 // Just handle the single function. 639 assert(Before.getData().size() == 1 && After.getData().size() == 1 && 640 "Expected only one function."); 641 CompareFunc(false, 0, Before.getData().begin()->getValue(), 642 After.getData().begin()->getValue()); 643 return; 644 } 645 646 unsigned Minor = 0; 647 FuncDataT<T> Missing(""); 648 IRDataT<T>::report(Before, After, 649 [&](const FuncDataT<T> *B, const FuncDataT<T> *A) { 650 assert((B || A) && "Both functions cannot be missing."); 651 if (!B) 652 B = &Missing; 653 else if (!A) 654 A = &Missing; 655 CompareFunc(true, Minor++, *B, *A); 656 }); 657 } 658 659 template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &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 auto *F = unwrapIR<Function>(IR); 668 if (!F) { 669 const auto *L = unwrapIR<Loop>(IR); 670 assert(L && "Unknown IR unit."); 671 F = L->getHeader()->getParent(); 672 } 673 assert(F && "Unknown IR unit."); 674 generateFunctionData(Data, *F); 675 } 676 677 template <typename T> 678 bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const Function &F) { 679 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) { 680 FuncDataT<T> FD(F.getEntryBlock().getName().str()); 681 int I = 0; 682 for (const auto &B : F) { 683 std::string BBName = B.getName().str(); 684 if (BBName.empty()) { 685 BBName = formatv("{0}", I); 686 ++I; 687 } 688 FD.getOrder().emplace_back(BBName); 689 FD.getData().insert({BBName, B}); 690 } 691 Data.getOrder().emplace_back(F.getName()); 692 Data.getData().insert({F.getName(), FD}); 693 return true; 694 } 695 return false; 696 } 697 698 PrintIRInstrumentation::~PrintIRInstrumentation() { 699 assert(PassRunDescriptorStack.empty() && 700 "PassRunDescriptorStack is not empty at exit"); 701 } 702 703 static SmallString<32> getIRFileDisplayName(Any IR) { 704 SmallString<32> Result; 705 raw_svector_ostream ResultStream(Result); 706 const Module *M = unwrapModule(IR); 707 stable_hash NameHash = stable_hash_combine_string(M->getName()); 708 unsigned int MaxHashWidth = sizeof(stable_hash) * 8 / 4; 709 write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth); 710 if (unwrapIR<Module>(IR)) { 711 ResultStream << "-module"; 712 } else if (const auto *F = unwrapIR<Function>(IR)) { 713 ResultStream << "-function-"; 714 stable_hash FunctionNameHash = stable_hash_combine_string(F->getName()); 715 write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower, 716 MaxHashWidth); 717 } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) { 718 ResultStream << "-scc-"; 719 stable_hash SCCNameHash = stable_hash_combine_string(C->getName()); 720 write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth); 721 } else if (const auto *L = unwrapIR<Loop>(IR)) { 722 ResultStream << "-loop-"; 723 stable_hash LoopNameHash = stable_hash_combine_string(L->getName()); 724 write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth); 725 } else { 726 llvm_unreachable("Unknown wrapped IR type"); 727 } 728 return Result; 729 } 730 731 std::string PrintIRInstrumentation::fetchDumpFilename(StringRef PassName, 732 Any IR) { 733 const StringRef RootDirectory = IRDumpDirectory; 734 assert(!RootDirectory.empty() && 735 "The flag -ir-dump-directory must be passed to dump IR to files"); 736 SmallString<128> ResultPath; 737 ResultPath += RootDirectory; 738 SmallString<64> Filename; 739 raw_svector_ostream FilenameStream(Filename); 740 FilenameStream << CurrentPassNumber; 741 FilenameStream << "-"; 742 FilenameStream << getIRFileDisplayName(IR); 743 FilenameStream << "-"; 744 FilenameStream << PassName; 745 sys::path::append(ResultPath, Filename); 746 return std::string(ResultPath); 747 } 748 749 enum class IRDumpFileSuffixType { 750 Before, 751 After, 752 Invalidated, 753 }; 754 755 static StringRef getFileSuffix(IRDumpFileSuffixType Type) { 756 static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll", 757 "-invalidated.ll"}; 758 return FileSuffixes[static_cast<size_t>(Type)]; 759 } 760 761 void PrintIRInstrumentation::pushPassRunDescriptor( 762 StringRef PassID, Any IR, std::string &DumpIRFilename) { 763 const Module *M = unwrapModule(IR); 764 PassRunDescriptorStack.emplace_back( 765 PassRunDescriptor(M, DumpIRFilename, getIRName(IR), PassID)); 766 } 767 768 PrintIRInstrumentation::PassRunDescriptor 769 PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) { 770 assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack"); 771 PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val(); 772 assert(Descriptor.PassID.equals(PassID) && 773 "malformed PassRunDescriptorStack"); 774 return Descriptor; 775 } 776 777 // Callers are responsible for closing the returned file descriptor 778 static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) { 779 std::error_code EC; 780 auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename); 781 if (!ParentPath.empty()) { 782 std::error_code EC = llvm::sys::fs::create_directories(ParentPath); 783 if (EC) 784 report_fatal_error(Twine("Failed to create directory ") + ParentPath + 785 " to support -ir-dump-directory: " + EC.message()); 786 } 787 int Result = 0; 788 EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways, 789 sys::fs::FA_Write, sys::fs::OF_None); 790 if (EC) 791 report_fatal_error(Twine("Failed to open ") + DumpIRFilename + 792 " to support -ir-dump-directory: " + EC.message()); 793 return Result; 794 } 795 796 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) { 797 if (isIgnored(PassID)) 798 return; 799 800 std::string DumpIRFilename; 801 if (!IRDumpDirectory.empty() && 802 (shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID))) 803 DumpIRFilename = fetchDumpFilename(PassID, IR); 804 805 // Saving Module for AfterPassInvalidated operations. 806 // Note: here we rely on a fact that we do not change modules while 807 // traversing the pipeline, so the latest captured module is good 808 // for all print operations that has not happen yet. 809 if (shouldPrintAfterPass(PassID)) 810 pushPassRunDescriptor(PassID, IR, DumpIRFilename); 811 812 if (!shouldPrintIR(IR)) 813 return; 814 815 ++CurrentPassNumber; 816 817 if (shouldPrintPassNumbers()) 818 dbgs() << " Running pass " << CurrentPassNumber << " " << PassID 819 << " on " << getIRName(IR) << "\n"; 820 821 if (!shouldPrintBeforePass(PassID)) 822 return; 823 824 auto WriteIRToStream = [&](raw_ostream &Stream) { 825 Stream << "; *** IR Dump Before "; 826 if (shouldPrintBeforePassNumber()) 827 Stream << CurrentPassNumber << "-"; 828 Stream << PassID << " on " << getIRName(IR) << " ***\n"; 829 unwrapAndPrint(Stream, IR); 830 }; 831 832 if (!DumpIRFilename.empty()) { 833 DumpIRFilename += getFileSuffix(IRDumpFileSuffixType::Before); 834 llvm::raw_fd_ostream DumpIRFileStream{ 835 prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true}; 836 WriteIRToStream(DumpIRFileStream); 837 } else { 838 WriteIRToStream(dbgs()); 839 } 840 } 841 842 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) { 843 if (isIgnored(PassID)) 844 return; 845 846 if (!shouldPrintAfterPass(PassID)) 847 return; 848 849 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID); 850 assert(StoredPassID == PassID && "mismatched PassID"); 851 852 if (!shouldPrintIR(IR) || !shouldPrintAfterPass(PassID)) 853 return; 854 855 auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) { 856 Stream << "; *** IR Dump " << StringRef(formatv("After {0}", PassID)) 857 << " on " << IRName << " ***\n"; 858 unwrapAndPrint(Stream, IR); 859 }; 860 861 if (!IRDumpDirectory.empty()) { 862 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and " 863 "should be set in printBeforePass"); 864 const std::string DumpIRFilenameWithSuffix = 865 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::After).str(); 866 llvm::raw_fd_ostream DumpIRFileStream{ 867 prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix), 868 /* shouldClose */ true}; 869 WriteIRToStream(DumpIRFileStream, IRName); 870 } else { 871 WriteIRToStream(dbgs(), IRName); 872 } 873 } 874 875 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) { 876 if (isIgnored(PassID)) 877 return; 878 879 if (!shouldPrintAfterPass(PassID)) 880 return; 881 882 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID); 883 assert(StoredPassID == PassID && "mismatched PassID"); 884 // Additional filtering (e.g. -filter-print-func) can lead to module 885 // printing being skipped. 886 if (!M || !shouldPrintAfterPass(PassID)) 887 return; 888 889 auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M, 890 const StringRef IRName) { 891 SmallString<20> Banner; 892 Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID, 893 IRName); 894 Stream << Banner << "\n"; 895 printIR(Stream, M); 896 }; 897 898 if (!IRDumpDirectory.empty()) { 899 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and " 900 "should be set in printBeforePass"); 901 const std::string DumpIRFilenameWithSuffix = 902 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::Invalidated).str(); 903 llvm::raw_fd_ostream DumpIRFileStream{ 904 prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix), 905 /* shouldClose */ true}; 906 WriteIRToStream(DumpIRFileStream, M, IRName); 907 } else { 908 WriteIRToStream(dbgs(), M, IRName); 909 } 910 } 911 912 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) { 913 if (shouldPrintBeforeAll()) 914 return true; 915 916 if (shouldPrintBeforePassNumber() && 917 CurrentPassNumber == PrintBeforePassNumber) 918 return true; 919 920 StringRef PassName = PIC->getPassNameForClassName(PassID); 921 return is_contained(printBeforePasses(), PassName); 922 } 923 924 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) { 925 if (shouldPrintAfterAll()) 926 return true; 927 928 StringRef PassName = PIC->getPassNameForClassName(PassID); 929 return is_contained(printAfterPasses(), PassName); 930 } 931 932 bool PrintIRInstrumentation::shouldPrintPassNumbers() { 933 return PrintPassNumbers; 934 } 935 936 bool PrintIRInstrumentation::shouldPrintBeforePassNumber() { 937 return PrintBeforePassNumber > 0; 938 } 939 940 void PrintIRInstrumentation::registerCallbacks( 941 PassInstrumentationCallbacks &PIC) { 942 this->PIC = &PIC; 943 944 // BeforePass callback is not just for printing, it also saves a Module 945 // for later use in AfterPassInvalidated. 946 if (shouldPrintPassNumbers() || shouldPrintBeforePassNumber() || 947 shouldPrintBeforeSomePass() || shouldPrintAfterSomePass()) 948 PIC.registerBeforeNonSkippedPassCallback( 949 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); }); 950 951 if (shouldPrintAfterSomePass()) { 952 PIC.registerAfterPassCallback( 953 [this](StringRef P, Any IR, const PreservedAnalyses &) { 954 this->printAfterPass(P, IR); 955 }); 956 PIC.registerAfterPassInvalidatedCallback( 957 [this](StringRef P, const PreservedAnalyses &) { 958 this->printAfterPassInvalidated(P); 959 }); 960 } 961 } 962 963 void OptNoneInstrumentation::registerCallbacks( 964 PassInstrumentationCallbacks &PIC) { 965 PIC.registerShouldRunOptionalPassCallback( 966 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); }); 967 } 968 969 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) { 970 const auto *F = unwrapIR<Function>(IR); 971 if (!F) { 972 if (const auto *L = unwrapIR<Loop>(IR)) 973 F = L->getHeader()->getParent(); 974 } 975 bool ShouldRun = !(F && F->hasOptNone()); 976 if (!ShouldRun && DebugLogging) { 977 errs() << "Skipping pass " << PassID << " on " << F->getName() 978 << " due to optnone attribute\n"; 979 } 980 return ShouldRun; 981 } 982 983 bool OptPassGateInstrumentation::shouldRun(StringRef PassName, Any IR) { 984 if (isIgnored(PassName)) 985 return true; 986 987 bool ShouldRun = 988 Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR)); 989 if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) { 990 // FIXME: print IR if limit is higher than number of opt-bisect 991 // invocations 992 this->HasWrittenIR = true; 993 const Module *M = unwrapModule(IR, /*Force=*/true); 994 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module"); 995 std::error_code EC; 996 raw_fd_ostream OS(OptBisectPrintIRPath, EC); 997 if (EC) 998 report_fatal_error(errorCodeToError(EC)); 999 M->print(OS, nullptr); 1000 } 1001 return ShouldRun; 1002 } 1003 1004 void OptPassGateInstrumentation::registerCallbacks( 1005 PassInstrumentationCallbacks &PIC) { 1006 OptPassGate &PassGate = Context.getOptPassGate(); 1007 if (!PassGate.isEnabled()) 1008 return; 1009 1010 PIC.registerShouldRunOptionalPassCallback([this](StringRef PassName, Any IR) { 1011 return this->shouldRun(PassName, IR); 1012 }); 1013 } 1014 1015 raw_ostream &PrintPassInstrumentation::print() { 1016 if (Opts.Indent) { 1017 assert(Indent >= 0); 1018 dbgs().indent(Indent); 1019 } 1020 return dbgs(); 1021 } 1022 1023 void PrintPassInstrumentation::registerCallbacks( 1024 PassInstrumentationCallbacks &PIC) { 1025 if (!Enabled) 1026 return; 1027 1028 std::vector<StringRef> SpecialPasses; 1029 if (!Opts.Verbose) { 1030 SpecialPasses.emplace_back("PassManager"); 1031 SpecialPasses.emplace_back("PassAdaptor"); 1032 } 1033 1034 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID, 1035 Any IR) { 1036 assert(!isSpecialPass(PassID, SpecialPasses) && 1037 "Unexpectedly skipping special pass"); 1038 1039 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n"; 1040 }); 1041 PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses]( 1042 StringRef PassID, Any IR) { 1043 if (isSpecialPass(PassID, SpecialPasses)) 1044 return; 1045 1046 auto &OS = print(); 1047 OS << "Running pass: " << PassID << " on " << getIRName(IR); 1048 if (const auto *F = unwrapIR<Function>(IR)) { 1049 unsigned Count = F->getInstructionCount(); 1050 OS << " (" << Count << " instruction"; 1051 if (Count != 1) 1052 OS << 's'; 1053 OS << ')'; 1054 } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) { 1055 int Count = C->size(); 1056 OS << " (" << Count << " node"; 1057 if (Count != 1) 1058 OS << 's'; 1059 OS << ')'; 1060 } 1061 OS << "\n"; 1062 Indent += 2; 1063 }); 1064 PIC.registerAfterPassCallback( 1065 [this, SpecialPasses](StringRef PassID, Any IR, 1066 const PreservedAnalyses &) { 1067 if (isSpecialPass(PassID, SpecialPasses)) 1068 return; 1069 1070 Indent -= 2; 1071 }); 1072 PIC.registerAfterPassInvalidatedCallback( 1073 [this, SpecialPasses](StringRef PassID, Any IR) { 1074 if (isSpecialPass(PassID, SpecialPasses)) 1075 return; 1076 1077 Indent -= 2; 1078 }); 1079 1080 if (!Opts.SkipAnalyses) { 1081 PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) { 1082 print() << "Running analysis: " << PassID << " on " << getIRName(IR) 1083 << "\n"; 1084 Indent += 2; 1085 }); 1086 PIC.registerAfterAnalysisCallback( 1087 [this](StringRef PassID, Any IR) { Indent -= 2; }); 1088 PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) { 1089 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR) 1090 << "\n"; 1091 }); 1092 PIC.registerAnalysesClearedCallback([this](StringRef IRName) { 1093 print() << "Clearing all analysis results for: " << IRName << "\n"; 1094 }); 1095 } 1096 } 1097 1098 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F, 1099 bool TrackBBLifetime) { 1100 if (TrackBBLifetime) 1101 BBGuards = DenseMap<intptr_t, BBGuard>(F->size()); 1102 for (const auto &BB : *F) { 1103 if (BBGuards) 1104 BBGuards->try_emplace(intptr_t(&BB), &BB); 1105 for (const auto *Succ : successors(&BB)) { 1106 Graph[&BB][Succ]++; 1107 if (BBGuards) 1108 BBGuards->try_emplace(intptr_t(Succ), Succ); 1109 } 1110 } 1111 } 1112 1113 static void printBBName(raw_ostream &out, const BasicBlock *BB) { 1114 if (BB->hasName()) { 1115 out << BB->getName() << "<" << BB << ">"; 1116 return; 1117 } 1118 1119 if (!BB->getParent()) { 1120 out << "unnamed_removed<" << BB << ">"; 1121 return; 1122 } 1123 1124 if (BB->isEntryBlock()) { 1125 out << "entry" 1126 << "<" << BB << ">"; 1127 return; 1128 } 1129 1130 unsigned FuncOrderBlockNum = 0; 1131 for (auto &FuncBB : *BB->getParent()) { 1132 if (&FuncBB == BB) 1133 break; 1134 FuncOrderBlockNum++; 1135 } 1136 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">"; 1137 } 1138 1139 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out, 1140 const CFG &Before, 1141 const CFG &After) { 1142 assert(!After.isPoisoned()); 1143 if (Before.isPoisoned()) { 1144 out << "Some blocks were deleted\n"; 1145 return; 1146 } 1147 1148 // Find and print graph differences. 1149 if (Before.Graph.size() != After.Graph.size()) 1150 out << "Different number of non-leaf basic blocks: before=" 1151 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n"; 1152 1153 for (auto &BB : Before.Graph) { 1154 auto BA = After.Graph.find(BB.first); 1155 if (BA == After.Graph.end()) { 1156 out << "Non-leaf block "; 1157 printBBName(out, BB.first); 1158 out << " is removed (" << BB.second.size() << " successors)\n"; 1159 } 1160 } 1161 1162 for (auto &BA : After.Graph) { 1163 auto BB = Before.Graph.find(BA.first); 1164 if (BB == Before.Graph.end()) { 1165 out << "Non-leaf block "; 1166 printBBName(out, BA.first); 1167 out << " is added (" << BA.second.size() << " successors)\n"; 1168 continue; 1169 } 1170 1171 if (BB->second == BA.second) 1172 continue; 1173 1174 out << "Different successors of block "; 1175 printBBName(out, BA.first); 1176 out << " (unordered):\n"; 1177 out << "- before (" << BB->second.size() << "): "; 1178 for (auto &SuccB : BB->second) { 1179 printBBName(out, SuccB.first); 1180 if (SuccB.second != 1) 1181 out << "(" << SuccB.second << "), "; 1182 else 1183 out << ", "; 1184 } 1185 out << "\n"; 1186 out << "- after (" << BA.second.size() << "): "; 1187 for (auto &SuccA : BA.second) { 1188 printBBName(out, SuccA.first); 1189 if (SuccA.second != 1) 1190 out << "(" << SuccA.second << "), "; 1191 else 1192 out << ", "; 1193 } 1194 out << "\n"; 1195 } 1196 } 1197 1198 // PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check 1199 // passes, that reported they kept CFG analyses up-to-date, did not actually 1200 // change CFG. This check is done as follows. Before every functional pass in 1201 // BeforeNonSkippedPassCallback a CFG snapshot (an instance of 1202 // PreservedCFGCheckerInstrumentation::CFG) is requested from 1203 // FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the 1204 // functional pass finishes and reports that CFGAnalyses or AllAnalyses are 1205 // up-to-date then the cached result of PreservedCFGCheckerAnalysis (if 1206 // available) is checked to be equal to a freshly created CFG snapshot. 1207 struct PreservedCFGCheckerAnalysis 1208 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> { 1209 friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>; 1210 1211 static AnalysisKey Key; 1212 1213 public: 1214 /// Provide the result type for this analysis pass. 1215 using Result = PreservedCFGCheckerInstrumentation::CFG; 1216 1217 /// Run the analysis pass over a function and produce CFG. 1218 Result run(Function &F, FunctionAnalysisManager &FAM) { 1219 return Result(&F, /* TrackBBLifetime */ true); 1220 } 1221 }; 1222 1223 AnalysisKey PreservedCFGCheckerAnalysis::Key; 1224 1225 struct PreservedFunctionHashAnalysis 1226 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> { 1227 static AnalysisKey Key; 1228 1229 struct FunctionHash { 1230 uint64_t Hash; 1231 }; 1232 1233 using Result = FunctionHash; 1234 1235 Result run(Function &F, FunctionAnalysisManager &FAM) { 1236 return Result{StructuralHash(F)}; 1237 } 1238 }; 1239 1240 AnalysisKey PreservedFunctionHashAnalysis::Key; 1241 1242 struct PreservedModuleHashAnalysis 1243 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> { 1244 static AnalysisKey Key; 1245 1246 struct ModuleHash { 1247 uint64_t Hash; 1248 }; 1249 1250 using Result = ModuleHash; 1251 1252 Result run(Module &F, ModuleAnalysisManager &FAM) { 1253 return Result{StructuralHash(F)}; 1254 } 1255 }; 1256 1257 AnalysisKey PreservedModuleHashAnalysis::Key; 1258 1259 bool PreservedCFGCheckerInstrumentation::CFG::invalidate( 1260 Function &F, const PreservedAnalyses &PA, 1261 FunctionAnalysisManager::Invalidator &) { 1262 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>(); 1263 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() || 1264 PAC.preservedSet<CFGAnalyses>()); 1265 } 1266 1267 static SmallVector<Function *, 1> GetFunctions(Any IR) { 1268 SmallVector<Function *, 1> Functions; 1269 1270 if (const auto *MaybeF = unwrapIR<Function>(IR)) { 1271 Functions.push_back(const_cast<Function *>(MaybeF)); 1272 } else if (const auto *MaybeM = unwrapIR<Module>(IR)) { 1273 for (Function &F : *const_cast<Module *>(MaybeM)) 1274 Functions.push_back(&F); 1275 } 1276 return Functions; 1277 } 1278 1279 void PreservedCFGCheckerInstrumentation::registerCallbacks( 1280 PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM) { 1281 if (!VerifyAnalysisInvalidation) 1282 return; 1283 1284 bool Registered = false; 1285 PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered]( 1286 StringRef P, Any IR) mutable { 1287 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS 1288 assert(&PassStack.emplace_back(P)); 1289 #endif 1290 (void)this; 1291 1292 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>( 1293 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true))) 1294 .getManager(); 1295 if (!Registered) { 1296 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); }); 1297 FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); }); 1298 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); }); 1299 Registered = true; 1300 } 1301 1302 for (Function *F : GetFunctions(IR)) { 1303 // Make sure a fresh CFG snapshot is available before the pass. 1304 FAM.getResult<PreservedCFGCheckerAnalysis>(*F); 1305 FAM.getResult<PreservedFunctionHashAnalysis>(*F); 1306 } 1307 1308 if (const auto *MPtr = unwrapIR<Module>(IR)) { 1309 auto &M = *const_cast<Module *>(MPtr); 1310 MAM.getResult<PreservedModuleHashAnalysis>(M); 1311 } 1312 }); 1313 1314 PIC.registerAfterPassInvalidatedCallback( 1315 [this](StringRef P, const PreservedAnalyses &PassPA) { 1316 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS 1317 assert(PassStack.pop_back_val() == P && 1318 "Before and After callbacks must correspond"); 1319 #endif 1320 (void)this; 1321 }); 1322 1323 PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR, 1324 const PreservedAnalyses &PassPA) { 1325 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS 1326 assert(PassStack.pop_back_val() == P && 1327 "Before and After callbacks must correspond"); 1328 #endif 1329 (void)this; 1330 1331 // We have to get the FAM via the MAM, rather than directly use a passed in 1332 // FAM because if MAM has not cached the FAM, it won't invalidate function 1333 // analyses in FAM. 1334 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>( 1335 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true))) 1336 .getManager(); 1337 1338 for (Function *F : GetFunctions(IR)) { 1339 if (auto *HashBefore = 1340 FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) { 1341 if (HashBefore->Hash != StructuralHash(*F)) { 1342 report_fatal_error(formatv( 1343 "Function @{0} changed by {1} without invalidating analyses", 1344 F->getName(), P)); 1345 } 1346 } 1347 1348 auto CheckCFG = [](StringRef Pass, StringRef FuncName, 1349 const CFG &GraphBefore, const CFG &GraphAfter) { 1350 if (GraphAfter == GraphBefore) 1351 return; 1352 1353 dbgs() 1354 << "Error: " << Pass 1355 << " does not invalidate CFG analyses but CFG changes detected in " 1356 "function @" 1357 << FuncName << ":\n"; 1358 CFG::printDiff(dbgs(), GraphBefore, GraphAfter); 1359 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass)); 1360 }; 1361 1362 if (auto *GraphBefore = 1363 FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F)) 1364 CheckCFG(P, F->getName(), *GraphBefore, 1365 CFG(F, /* TrackBBLifetime */ false)); 1366 } 1367 if (const auto *MPtr = unwrapIR<Module>(IR)) { 1368 auto &M = *const_cast<Module *>(MPtr); 1369 if (auto *HashBefore = 1370 MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) { 1371 if (HashBefore->Hash != StructuralHash(M)) { 1372 report_fatal_error(formatv( 1373 "Module changed by {0} without invalidating analyses", P)); 1374 } 1375 } 1376 } 1377 }); 1378 } 1379 1380 void VerifyInstrumentation::registerCallbacks( 1381 PassInstrumentationCallbacks &PIC) { 1382 PIC.registerAfterPassCallback( 1383 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) { 1384 if (isIgnored(P) || P == "VerifierPass") 1385 return; 1386 const auto *F = unwrapIR<Function>(IR); 1387 if (!F) { 1388 if (const auto *L = unwrapIR<Loop>(IR)) 1389 F = L->getHeader()->getParent(); 1390 } 1391 1392 if (F) { 1393 if (DebugLogging) 1394 dbgs() << "Verifying function " << F->getName() << "\n"; 1395 1396 if (verifyFunction(*F, &errs())) 1397 report_fatal_error(formatv("Broken function found after pass " 1398 "\"{0}\", compilation aborted!", 1399 P)); 1400 } else { 1401 const auto *M = unwrapIR<Module>(IR); 1402 if (!M) { 1403 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) 1404 M = C->begin()->getFunction().getParent(); 1405 } 1406 1407 if (M) { 1408 if (DebugLogging) 1409 dbgs() << "Verifying module " << M->getName() << "\n"; 1410 1411 if (verifyModule(*M, &errs())) 1412 report_fatal_error(formatv("Broken module found after pass " 1413 "\"{0}\", compilation aborted!", 1414 P)); 1415 } 1416 } 1417 }); 1418 } 1419 1420 InLineChangePrinter::~InLineChangePrinter() = default; 1421 1422 void InLineChangePrinter::generateIRRepresentation(Any IR, 1423 StringRef PassID, 1424 IRDataT<EmptyData> &D) { 1425 IRComparer<EmptyData>::analyzeIR(IR, D); 1426 } 1427 1428 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name, 1429 const IRDataT<EmptyData> &Before, 1430 const IRDataT<EmptyData> &After, 1431 Any IR) { 1432 SmallString<20> Banner = 1433 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name); 1434 Out << Banner; 1435 IRComparer<EmptyData>(Before, After) 1436 .compare(getModuleForComparison(IR), 1437 [&](bool InModule, unsigned Minor, 1438 const FuncDataT<EmptyData> &Before, 1439 const FuncDataT<EmptyData> &After) -> void { 1440 handleFunctionCompare(Name, "", PassID, " on ", InModule, 1441 Minor, Before, After); 1442 }); 1443 Out << "\n"; 1444 } 1445 1446 void InLineChangePrinter::handleFunctionCompare( 1447 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, 1448 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before, 1449 const FuncDataT<EmptyData> &After) { 1450 // Print a banner when this is being shown in the context of a module 1451 if (InModule) 1452 Out << "\n*** IR for function " << Name << " ***\n"; 1453 1454 FuncDataT<EmptyData>::report( 1455 Before, After, 1456 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) { 1457 StringRef BStr = B ? B->getBody() : "\n"; 1458 StringRef AStr = A ? A->getBody() : "\n"; 1459 const std::string Removed = 1460 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n"; 1461 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n"; 1462 const std::string NoChange = " %l\n"; 1463 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange); 1464 }); 1465 } 1466 1467 void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) { 1468 if (PrintChanged == ChangePrinter::DiffVerbose || 1469 PrintChanged == ChangePrinter::DiffQuiet || 1470 PrintChanged == ChangePrinter::ColourDiffVerbose || 1471 PrintChanged == ChangePrinter::ColourDiffQuiet) 1472 TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC); 1473 } 1474 1475 TimeProfilingPassesHandler::TimeProfilingPassesHandler() {} 1476 1477 void TimeProfilingPassesHandler::registerCallbacks( 1478 PassInstrumentationCallbacks &PIC) { 1479 if (!getTimeTraceProfilerInstance()) 1480 return; 1481 PIC.registerBeforeNonSkippedPassCallback( 1482 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); }); 1483 PIC.registerAfterPassCallback( 1484 [this](StringRef P, Any IR, const PreservedAnalyses &) { 1485 this->runAfterPass(); 1486 }, 1487 true); 1488 PIC.registerAfterPassInvalidatedCallback( 1489 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); }, 1490 true); 1491 PIC.registerBeforeAnalysisCallback( 1492 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); }); 1493 PIC.registerAfterAnalysisCallback( 1494 [this](StringRef P, Any IR) { this->runAfterPass(); }, true); 1495 } 1496 1497 void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) { 1498 timeTraceProfilerBegin(PassID, getIRName(IR)); 1499 } 1500 1501 void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); } 1502 1503 namespace { 1504 1505 class DisplayNode; 1506 class DotCfgDiffDisplayGraph; 1507 1508 // Base class for a node or edge in the dot-cfg-changes graph. 1509 class DisplayElement { 1510 public: 1511 // Is this in before, after, or both? 1512 StringRef getColour() const { return Colour; } 1513 1514 protected: 1515 DisplayElement(StringRef Colour) : Colour(Colour) {} 1516 const StringRef Colour; 1517 }; 1518 1519 // An edge representing a transition between basic blocks in the 1520 // dot-cfg-changes graph. 1521 class DisplayEdge : public DisplayElement { 1522 public: 1523 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour) 1524 : DisplayElement(Colour), Value(Value), Node(Node) {} 1525 // The value on which the transition is made. 1526 std::string getValue() const { return Value; } 1527 // The node (representing a basic block) reached by this transition. 1528 const DisplayNode &getDestinationNode() const { return Node; } 1529 1530 protected: 1531 std::string Value; 1532 const DisplayNode &Node; 1533 }; 1534 1535 // A node in the dot-cfg-changes graph which represents a basic block. 1536 class DisplayNode : public DisplayElement { 1537 public: 1538 // \p C is the content for the node, \p T indicates the colour for the 1539 // outline of the node 1540 DisplayNode(std::string Content, StringRef Colour) 1541 : DisplayElement(Colour), Content(Content) {} 1542 1543 // Iterator to the child nodes. Required by GraphWriter. 1544 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator; 1545 ChildIterator children_begin() const { return Children.cbegin(); } 1546 ChildIterator children_end() const { return Children.cend(); } 1547 1548 // Iterator for the edges. Required by GraphWriter. 1549 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator; 1550 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); } 1551 EdgeIterator edges_end() const { return EdgePtrs.cend(); } 1552 1553 // Create an edge to \p Node on value \p Value, with colour \p Colour. 1554 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour); 1555 1556 // Return the content of this node. 1557 std::string getContent() const { return Content; } 1558 1559 // Return the edge to node \p S. 1560 const DisplayEdge &getEdge(const DisplayNode &To) const { 1561 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge."); 1562 return *EdgeMap.find(&To)->second; 1563 } 1564 1565 // Return the value for the transition to basic block \p S. 1566 // Required by GraphWriter. 1567 std::string getEdgeSourceLabel(const DisplayNode &Sink) const { 1568 return getEdge(Sink).getValue(); 1569 } 1570 1571 void createEdgeMap(); 1572 1573 protected: 1574 const std::string Content; 1575 1576 // Place to collect all of the edges. Once they are all in the vector, 1577 // the vector will not reallocate so then we can use pointers to them, 1578 // which are required by the graph writing routines. 1579 std::vector<DisplayEdge> Edges; 1580 1581 std::vector<DisplayEdge *> EdgePtrs; 1582 std::unordered_set<DisplayNode *> Children; 1583 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap; 1584 1585 // Safeguard adding of edges. 1586 bool AllEdgesCreated = false; 1587 }; 1588 1589 // Class representing a difference display (corresponds to a pdf file). 1590 class DotCfgDiffDisplayGraph { 1591 public: 1592 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {} 1593 1594 // Generate the file into \p DotFile. 1595 void generateDotFile(StringRef DotFile); 1596 1597 // Iterator to the nodes. Required by GraphWriter. 1598 using NodeIterator = std::vector<DisplayNode *>::const_iterator; 1599 NodeIterator nodes_begin() const { 1600 assert(NodeGenerationComplete && "Unexpected children iterator creation"); 1601 return NodePtrs.cbegin(); 1602 } 1603 NodeIterator nodes_end() const { 1604 assert(NodeGenerationComplete && "Unexpected children iterator creation"); 1605 return NodePtrs.cend(); 1606 } 1607 1608 // Record the index of the entry node. At this point, we can build up 1609 // vectors of pointers that are required by the graph routines. 1610 void setEntryNode(unsigned N) { 1611 // At this point, there will be no new nodes. 1612 assert(!NodeGenerationComplete && "Unexpected node creation"); 1613 NodeGenerationComplete = true; 1614 for (auto &N : Nodes) 1615 NodePtrs.emplace_back(&N); 1616 1617 EntryNode = NodePtrs[N]; 1618 } 1619 1620 // Create a node. 1621 void createNode(std::string C, StringRef Colour) { 1622 assert(!NodeGenerationComplete && "Unexpected node creation"); 1623 Nodes.emplace_back(C, Colour); 1624 } 1625 // Return the node at index \p N to avoid problems with vectors reallocating. 1626 DisplayNode &getNode(unsigned N) { 1627 assert(N < Nodes.size() && "Node is out of bounds"); 1628 return Nodes[N]; 1629 } 1630 unsigned size() const { 1631 assert(NodeGenerationComplete && "Unexpected children iterator creation"); 1632 return Nodes.size(); 1633 } 1634 1635 // Return the name of the graph. Required by GraphWriter. 1636 std::string getGraphName() const { return GraphName; } 1637 1638 // Return the string representing the differences for basic block \p Node. 1639 // Required by GraphWriter. 1640 std::string getNodeLabel(const DisplayNode &Node) const { 1641 return Node.getContent(); 1642 } 1643 1644 // Return a string with colour information for Dot. Required by GraphWriter. 1645 std::string getNodeAttributes(const DisplayNode &Node) const { 1646 return attribute(Node.getColour()); 1647 } 1648 1649 // Return a string with colour information for Dot. Required by GraphWriter. 1650 std::string getEdgeColorAttr(const DisplayNode &From, 1651 const DisplayNode &To) const { 1652 return attribute(From.getEdge(To).getColour()); 1653 } 1654 1655 // Get the starting basic block. Required by GraphWriter. 1656 DisplayNode *getEntryNode() const { 1657 assert(NodeGenerationComplete && "Unexpected children iterator creation"); 1658 return EntryNode; 1659 } 1660 1661 protected: 1662 // Return the string containing the colour to use as a Dot attribute. 1663 std::string attribute(StringRef Colour) const { 1664 return "color=" + Colour.str(); 1665 } 1666 1667 bool NodeGenerationComplete = false; 1668 const std::string GraphName; 1669 std::vector<DisplayNode> Nodes; 1670 std::vector<DisplayNode *> NodePtrs; 1671 DisplayNode *EntryNode = nullptr; 1672 }; 1673 1674 void DisplayNode::createEdge(StringRef Value, DisplayNode &Node, 1675 StringRef Colour) { 1676 assert(!AllEdgesCreated && "Expected to be able to still create edges."); 1677 Edges.emplace_back(Value.str(), Node, Colour); 1678 Children.insert(&Node); 1679 } 1680 1681 void DisplayNode::createEdgeMap() { 1682 // No more edges will be added so we can now use pointers to the edges 1683 // as the vector will not grow and reallocate. 1684 AllEdgesCreated = true; 1685 for (auto &E : Edges) 1686 EdgeMap.insert({&E.getDestinationNode(), &E}); 1687 } 1688 1689 class DotCfgDiffNode; 1690 class DotCfgDiff; 1691 1692 // A class representing a basic block in the Dot difference graph. 1693 class DotCfgDiffNode { 1694 public: 1695 DotCfgDiffNode() = delete; 1696 1697 // Create a node in Dot difference graph \p G representing the basic block 1698 // represented by \p BD with colour \p Colour (where it exists). 1699 DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD, 1700 StringRef Colour) 1701 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {} 1702 DotCfgDiffNode(const DotCfgDiffNode &DN) 1703 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]}, 1704 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children), 1705 Edges(DN.Edges) {} 1706 1707 unsigned getIndex() const { return N; } 1708 1709 // The label of the basic block 1710 StringRef getLabel() const { 1711 assert(Data[0] && "Expected Data[0] to be set."); 1712 return Data[0]->getLabel(); 1713 } 1714 // Return the colour for this block 1715 StringRef getColour() const { return Colour; } 1716 // Change this basic block from being only in before to being common. 1717 // Save the pointer to \p Other. 1718 void setCommon(const BlockDataT<DCData> &Other) { 1719 assert(!Data[1] && "Expected only one block datum"); 1720 Data[1] = &Other; 1721 Colour = CommonColour; 1722 } 1723 // Add an edge to \p E of colour {\p Value, \p Colour}. 1724 void addEdge(unsigned E, StringRef Value, StringRef Colour) { 1725 // This is a new edge or it is an edge being made common. 1726 assert((EdgesMap.count(E) == 0 || Colour == CommonColour) && 1727 "Unexpected edge count and color."); 1728 EdgesMap[E] = {Value.str(), Colour}; 1729 } 1730 // Record the children and create edges. 1731 void finalize(DotCfgDiff &G); 1732 1733 // Return the colour of the edge to node \p S. 1734 StringRef getEdgeColour(const unsigned S) const { 1735 assert(EdgesMap.count(S) == 1 && "Expected to find edge."); 1736 return EdgesMap.at(S).second; 1737 } 1738 1739 // Return the string representing the basic block. 1740 std::string getBodyContent() const; 1741 1742 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode, 1743 std::map<const unsigned, unsigned> &NodeMap) const; 1744 1745 protected: 1746 DotCfgDiff &Graph; 1747 const unsigned N; 1748 const BlockDataT<DCData> *Data[2]; 1749 StringRef Colour; 1750 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap; 1751 std::vector<unsigned> Children; 1752 std::vector<unsigned> Edges; 1753 }; 1754 1755 // Class representing the difference graph between two functions. 1756 class DotCfgDiff { 1757 public: 1758 // \p Title is the title given to the graph. \p EntryNodeName is the 1759 // entry node for the function. \p Before and \p After are the before 1760 // after versions of the function, respectively. \p Dir is the directory 1761 // in which to store the results. 1762 DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before, 1763 const FuncDataT<DCData> &After); 1764 1765 DotCfgDiff(const DotCfgDiff &) = delete; 1766 DotCfgDiff &operator=(const DotCfgDiff &) = delete; 1767 1768 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title, 1769 StringRef EntryNodeName); 1770 1771 // Return a string consisting of the labels for the \p Source and \p Sink. 1772 // The combination allows distinguishing changing transitions on the 1773 // same value (ie, a transition went to X before and goes to Y after). 1774 // Required by GraphWriter. 1775 StringRef getEdgeSourceLabel(const unsigned &Source, 1776 const unsigned &Sink) const { 1777 std::string S = 1778 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str(); 1779 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label."); 1780 return EdgeLabels.find(S)->getValue(); 1781 } 1782 1783 // Return the number of basic blocks (nodes). Required by GraphWriter. 1784 unsigned size() const { return Nodes.size(); } 1785 1786 const DotCfgDiffNode &getNode(unsigned N) const { 1787 assert(N < Nodes.size() && "Unexpected index for node reference"); 1788 return Nodes[N]; 1789 } 1790 1791 protected: 1792 // Return the string surrounded by HTML to make it the appropriate colour. 1793 std::string colourize(std::string S, StringRef Colour) const; 1794 1795 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) { 1796 unsigned Pos = Nodes.size(); 1797 Nodes.emplace_back(*this, Pos, BD, C); 1798 NodePosition.insert({Label, Pos}); 1799 } 1800 1801 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the 1802 // display graph is separated out, which would remove the need for 1803 // NodePosition. 1804 std::vector<DotCfgDiffNode> Nodes; 1805 StringMap<unsigned> NodePosition; 1806 const std::string GraphName; 1807 1808 StringMap<std::string> EdgeLabels; 1809 }; 1810 1811 std::string DotCfgDiffNode::getBodyContent() const { 1812 if (Colour == CommonColour) { 1813 assert(Data[1] && "Expected Data[1] to be set."); 1814 1815 StringRef SR[2]; 1816 for (unsigned I = 0; I < 2; ++I) { 1817 SR[I] = Data[I]->getBody(); 1818 // drop initial '\n' if present 1819 if (SR[I][0] == '\n') 1820 SR[I] = SR[I].drop_front(); 1821 // drop predecessors as they can be big and are redundant 1822 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front(); 1823 } 1824 1825 SmallString<80> OldLineFormat = formatv( 1826 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour); 1827 SmallString<80> NewLineFormat = formatv( 1828 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour); 1829 SmallString<80> UnchangedLineFormat = formatv( 1830 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour); 1831 std::string Diff = Data[0]->getLabel().str(); 1832 Diff += ":\n<BR align=\"left\"/>" + 1833 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]), 1834 OldLineFormat, NewLineFormat, UnchangedLineFormat); 1835 1836 // Diff adds in some empty colour changes which are not valid HTML 1837 // so remove them. Colours are all lowercase alpha characters (as 1838 // listed in https://graphviz.org/pdf/dotguide.pdf). 1839 Regex R("<FONT COLOR=\"\\w+\"></FONT>"); 1840 while (true) { 1841 std::string Error; 1842 std::string S = R.sub("", Diff, &Error); 1843 if (Error != "") 1844 return Error; 1845 if (S == Diff) 1846 return Diff; 1847 Diff = S; 1848 } 1849 llvm_unreachable("Should not get here"); 1850 } 1851 1852 // Put node out in the appropriate colour. 1853 assert(!Data[1] && "Data[1] is set unexpectedly."); 1854 std::string Body = makeHTMLReady(Data[0]->getBody()); 1855 const StringRef BS = Body; 1856 StringRef BS1 = BS; 1857 // Drop leading newline, if present. 1858 if (BS.front() == '\n') 1859 BS1 = BS1.drop_front(1); 1860 // Get label. 1861 StringRef Label = BS1.take_until([](char C) { return C == ':'; }); 1862 // drop predecessors as they can be big and are redundant 1863 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front(); 1864 1865 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":"; 1866 1867 // align each line to the left. 1868 while (BS1.size()) { 1869 S.append("<BR align=\"left\"/>"); 1870 StringRef Line = BS1.take_until([](char C) { return C == '\n'; }); 1871 S.append(Line.str()); 1872 BS1 = BS1.drop_front(Line.size() + 1); 1873 } 1874 S.append("<BR align=\"left\"/></FONT>"); 1875 return S; 1876 } 1877 1878 std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const { 1879 if (S.length() == 0) 1880 return S; 1881 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>"; 1882 } 1883 1884 DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before, 1885 const FuncDataT<DCData> &After) 1886 : GraphName(Title.str()) { 1887 StringMap<StringRef> EdgesMap; 1888 1889 // Handle each basic block in the before IR. 1890 for (auto &B : Before.getData()) { 1891 StringRef Label = B.getKey(); 1892 const BlockDataT<DCData> &BD = B.getValue(); 1893 createNode(Label, BD, BeforeColour); 1894 1895 // Create transitions with names made up of the from block label, the value 1896 // on which the transition is made and the to block label. 1897 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(), 1898 E = BD.getData().end(); 1899 Sink != E; ++Sink) { 1900 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " + 1901 BD.getData().getSuccessorLabel(Sink->getKey()).str(); 1902 EdgesMap.insert({Key, BeforeColour}); 1903 } 1904 } 1905 1906 // Handle each basic block in the after IR 1907 for (auto &A : After.getData()) { 1908 StringRef Label = A.getKey(); 1909 const BlockDataT<DCData> &BD = A.getValue(); 1910 unsigned C = NodePosition.count(Label); 1911 if (C == 0) 1912 // This only exists in the after IR. Create the node. 1913 createNode(Label, BD, AfterColour); 1914 else { 1915 assert(C == 1 && "Unexpected multiple nodes."); 1916 Nodes[NodePosition[Label]].setCommon(BD); 1917 } 1918 // Add in the edges between the nodes (as common or only in after). 1919 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(), 1920 E = BD.getData().end(); 1921 Sink != E; ++Sink) { 1922 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " + 1923 BD.getData().getSuccessorLabel(Sink->getKey()).str(); 1924 unsigned C = EdgesMap.count(Key); 1925 if (C == 0) 1926 EdgesMap.insert({Key, AfterColour}); 1927 else { 1928 EdgesMap[Key] = CommonColour; 1929 } 1930 } 1931 } 1932 1933 // Now go through the map of edges and add them to the node. 1934 for (auto &E : EdgesMap) { 1935 // Extract the source, sink and value from the edge key. 1936 StringRef S = E.getKey(); 1937 auto SP1 = S.rsplit(' '); 1938 auto &SourceSink = SP1.first; 1939 auto SP2 = SourceSink.split(' '); 1940 StringRef Source = SP2.first; 1941 StringRef Sink = SP2.second; 1942 StringRef Value = SP1.second; 1943 1944 assert(NodePosition.count(Source) == 1 && "Expected to find node."); 1945 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]]; 1946 assert(NodePosition.count(Sink) == 1 && "Expected to find node."); 1947 unsigned SinkNode = NodePosition[Sink]; 1948 StringRef Colour = E.second; 1949 1950 // Look for an edge from Source to Sink 1951 if (EdgeLabels.count(SourceSink) == 0) 1952 EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)}); 1953 else { 1954 StringRef V = EdgeLabels.find(SourceSink)->getValue(); 1955 std::string NV = colourize(V.str() + " " + Value.str(), Colour); 1956 Colour = CommonColour; 1957 EdgeLabels[SourceSink] = NV; 1958 } 1959 SourceNode.addEdge(SinkNode, Value, Colour); 1960 } 1961 for (auto &I : Nodes) 1962 I.finalize(*this); 1963 } 1964 1965 DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title, 1966 StringRef EntryNodeName) { 1967 assert(NodePosition.count(EntryNodeName) == 1 && 1968 "Expected to find entry block in map."); 1969 unsigned Entry = NodePosition[EntryNodeName]; 1970 assert(Entry < Nodes.size() && "Expected to find entry node"); 1971 DotCfgDiffDisplayGraph G(Title.str()); 1972 1973 std::map<const unsigned, unsigned> NodeMap; 1974 1975 int EntryIndex = -1; 1976 unsigned Index = 0; 1977 for (auto &I : Nodes) { 1978 if (I.getIndex() == Entry) 1979 EntryIndex = Index; 1980 G.createNode(I.getBodyContent(), I.getColour()); 1981 NodeMap.insert({I.getIndex(), Index++}); 1982 } 1983 assert(EntryIndex >= 0 && "Expected entry node index to be set."); 1984 G.setEntryNode(EntryIndex); 1985 1986 for (auto &I : NodeMap) { 1987 unsigned SourceNode = I.first; 1988 unsigned DisplayNode = I.second; 1989 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap); 1990 } 1991 return G; 1992 } 1993 1994 void DotCfgDiffNode::createDisplayEdges( 1995 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex, 1996 std::map<const unsigned, unsigned> &NodeMap) const { 1997 1998 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex); 1999 2000 for (auto I : Edges) { 2001 unsigned SinkNodeIndex = I; 2002 StringRef Colour = getEdgeColour(SinkNodeIndex); 2003 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex); 2004 2005 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex); 2006 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex()); 2007 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour); 2008 } 2009 SourceDisplayNode.createEdgeMap(); 2010 } 2011 2012 void DotCfgDiffNode::finalize(DotCfgDiff &G) { 2013 for (auto E : EdgesMap) { 2014 Children.emplace_back(E.first); 2015 Edges.emplace_back(E.first); 2016 } 2017 } 2018 2019 } // namespace 2020 2021 namespace llvm { 2022 2023 template <> struct GraphTraits<DotCfgDiffDisplayGraph *> { 2024 using NodeRef = const DisplayNode *; 2025 using ChildIteratorType = DisplayNode::ChildIterator; 2026 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator; 2027 using EdgeRef = const DisplayEdge *; 2028 using ChildEdgeIterator = DisplayNode::EdgeIterator; 2029 2030 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) { 2031 return G->getEntryNode(); 2032 } 2033 static ChildIteratorType child_begin(NodeRef N) { 2034 return N->children_begin(); 2035 } 2036 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); } 2037 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) { 2038 return G->nodes_begin(); 2039 } 2040 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) { 2041 return G->nodes_end(); 2042 } 2043 static ChildEdgeIterator child_edge_begin(NodeRef N) { 2044 return N->edges_begin(); 2045 } 2046 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); } 2047 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); } 2048 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); } 2049 }; 2050 2051 template <> 2052 struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits { 2053 explicit DOTGraphTraits(bool Simple = false) 2054 : DefaultDOTGraphTraits(Simple) {} 2055 2056 static bool renderNodesUsingHTML() { return true; } 2057 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) { 2058 return DiffData->getGraphName(); 2059 } 2060 static std::string 2061 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) { 2062 return "\tsize=\"190, 190\";\n"; 2063 } 2064 static std::string getNodeLabel(const DisplayNode *Node, 2065 const DotCfgDiffDisplayGraph *DiffData) { 2066 return DiffData->getNodeLabel(*Node); 2067 } 2068 static std::string getNodeAttributes(const DisplayNode *Node, 2069 const DotCfgDiffDisplayGraph *DiffData) { 2070 return DiffData->getNodeAttributes(*Node); 2071 } 2072 static std::string getEdgeSourceLabel(const DisplayNode *From, 2073 DisplayNode::ChildIterator &To) { 2074 return From->getEdgeSourceLabel(**To); 2075 } 2076 static std::string getEdgeAttributes(const DisplayNode *From, 2077 DisplayNode::ChildIterator &To, 2078 const DotCfgDiffDisplayGraph *DiffData) { 2079 return DiffData->getEdgeColorAttr(*From, **To); 2080 } 2081 }; 2082 2083 } // namespace llvm 2084 2085 namespace { 2086 2087 void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) { 2088 std::error_code EC; 2089 raw_fd_ostream OutStream(DotFile, EC); 2090 if (EC) { 2091 errs() << "Error: " << EC.message() << "\n"; 2092 return; 2093 } 2094 WriteGraph(OutStream, this, false); 2095 OutStream.flush(); 2096 OutStream.close(); 2097 } 2098 2099 } // namespace 2100 2101 namespace llvm { 2102 2103 DCData::DCData(const BasicBlock &B) { 2104 // Build up transition labels. 2105 const Instruction *Term = B.getTerminator(); 2106 if (const BranchInst *Br = dyn_cast<const BranchInst>(Term)) 2107 if (Br->isUnconditional()) 2108 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), ""); 2109 else { 2110 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true"); 2111 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false"); 2112 } 2113 else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) { 2114 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(), 2115 "default"); 2116 for (auto &C : Sw->cases()) { 2117 assert(C.getCaseValue() && "Expected to find case value."); 2118 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue()); 2119 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value); 2120 } 2121 } else 2122 for (const_succ_iterator I = succ_begin(&B), E = succ_end(&B); I != E; ++I) 2123 addSuccessorLabel((*I)->getName().str(), ""); 2124 } 2125 2126 DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose) 2127 : ChangeReporter<IRDataT<DCData>>(Verbose) {} 2128 2129 void DotCfgChangeReporter::handleFunctionCompare( 2130 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, 2131 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before, 2132 const FuncDataT<DCData> &After) { 2133 assert(HTML && "Expected outstream to be set"); 2134 SmallString<8> Extender; 2135 SmallString<8> Number; 2136 // Handle numbering and file names. 2137 if (InModule) { 2138 Extender = formatv("{0}_{1}", N, Minor); 2139 Number = formatv("{0}.{1}", N, Minor); 2140 } else { 2141 Extender = formatv("{0}", N); 2142 Number = formatv("{0}", N); 2143 } 2144 // Create a temporary file name for the dot file. 2145 SmallVector<char, 128> SV; 2146 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true); 2147 std::string DotFile = Twine(SV).str(); 2148 2149 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender); 2150 SmallString<200> Text; 2151 2152 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID), 2153 Divider, Name); 2154 2155 DotCfgDiff Diff(Text, Before, After); 2156 std::string EntryBlockName = After.getEntryBlockName(); 2157 // Use the before entry block if the after entry block was removed. 2158 if (EntryBlockName == "") 2159 EntryBlockName = Before.getEntryBlockName(); 2160 assert(EntryBlockName != "" && "Expected to find entry block"); 2161 2162 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName); 2163 DG.generateDotFile(DotFile); 2164 2165 *HTML << genHTML(Text, DotFile, PDFFileName); 2166 std::error_code EC = sys::fs::remove(DotFile); 2167 if (EC) 2168 errs() << "Error: " << EC.message() << "\n"; 2169 } 2170 2171 std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile, 2172 StringRef PDFFileName) { 2173 SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName); 2174 // Create the PDF file. 2175 static ErrorOr<std::string> DotExe = sys::findProgramByName(DotBinary); 2176 if (!DotExe) 2177 return "Unable to find dot executable."; 2178 2179 StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile}; 2180 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt); 2181 if (Result < 0) 2182 return "Error executing system dot."; 2183 2184 // Create the HTML tag refering to the PDF file. 2185 SmallString<200> S = formatv( 2186 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text); 2187 return S.c_str(); 2188 } 2189 2190 void DotCfgChangeReporter::handleInitialIR(Any IR) { 2191 assert(HTML && "Expected outstream to be set"); 2192 *HTML << "<button type=\"button\" class=\"collapsible\">0. " 2193 << "Initial IR (by function)</button>\n" 2194 << "<div class=\"content\">\n" 2195 << " <p>\n"; 2196 // Create representation of IR 2197 IRDataT<DCData> Data; 2198 IRComparer<DCData>::analyzeIR(IR, Data); 2199 // Now compare it against itself, which will have everything the 2200 // same and will generate the files. 2201 IRComparer<DCData>(Data, Data) 2202 .compare(getModuleForComparison(IR), 2203 [&](bool InModule, unsigned Minor, 2204 const FuncDataT<DCData> &Before, 2205 const FuncDataT<DCData> &After) -> void { 2206 handleFunctionCompare("", " ", "Initial IR", "", InModule, 2207 Minor, Before, After); 2208 }); 2209 *HTML << " </p>\n" 2210 << "</div><br/>\n"; 2211 ++N; 2212 } 2213 2214 void DotCfgChangeReporter::generateIRRepresentation(Any IR, StringRef PassID, 2215 IRDataT<DCData> &Data) { 2216 IRComparer<DCData>::analyzeIR(IR, Data); 2217 } 2218 2219 void DotCfgChangeReporter::omitAfter(StringRef PassID, std::string &Name) { 2220 assert(HTML && "Expected outstream to be set"); 2221 SmallString<20> Banner = 2222 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n", 2223 N, makeHTMLReady(PassID), Name); 2224 *HTML << Banner; 2225 ++N; 2226 } 2227 2228 void DotCfgChangeReporter::handleAfter(StringRef PassID, std::string &Name, 2229 const IRDataT<DCData> &Before, 2230 const IRDataT<DCData> &After, Any IR) { 2231 assert(HTML && "Expected outstream to be set"); 2232 IRComparer<DCData>(Before, After) 2233 .compare(getModuleForComparison(IR), 2234 [&](bool InModule, unsigned Minor, 2235 const FuncDataT<DCData> &Before, 2236 const FuncDataT<DCData> &After) -> void { 2237 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule, 2238 Minor, Before, After); 2239 }); 2240 *HTML << " </p></div>\n"; 2241 ++N; 2242 } 2243 2244 void DotCfgChangeReporter::handleInvalidated(StringRef PassID) { 2245 assert(HTML && "Expected outstream to be set"); 2246 SmallString<20> Banner = 2247 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID)); 2248 *HTML << Banner; 2249 ++N; 2250 } 2251 2252 void DotCfgChangeReporter::handleFiltered(StringRef PassID, std::string &Name) { 2253 assert(HTML && "Expected outstream to be set"); 2254 SmallString<20> Banner = 2255 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N, 2256 makeHTMLReady(PassID), Name); 2257 *HTML << Banner; 2258 ++N; 2259 } 2260 2261 void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) { 2262 assert(HTML && "Expected outstream to be set"); 2263 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N, 2264 makeHTMLReady(PassID), Name); 2265 *HTML << Banner; 2266 ++N; 2267 } 2268 2269 bool DotCfgChangeReporter::initializeHTML() { 2270 std::error_code EC; 2271 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC); 2272 if (EC) { 2273 HTML = nullptr; 2274 return false; 2275 } 2276 2277 *HTML << "<!doctype html>" 2278 << "<html>" 2279 << "<head>" 2280 << "<style>.collapsible { " 2281 << "background-color: #777;" 2282 << " color: white;" 2283 << " cursor: pointer;" 2284 << " padding: 18px;" 2285 << " width: 100%;" 2286 << " border: none;" 2287 << " text-align: left;" 2288 << " outline: none;" 2289 << " font-size: 15px;" 2290 << "} .active, .collapsible:hover {" 2291 << " background-color: #555;" 2292 << "} .content {" 2293 << " padding: 0 18px;" 2294 << " display: none;" 2295 << " overflow: hidden;" 2296 << " background-color: #f1f1f1;" 2297 << "}" 2298 << "</style>" 2299 << "<title>passes.html</title>" 2300 << "</head>\n" 2301 << "<body>"; 2302 return true; 2303 } 2304 2305 DotCfgChangeReporter::~DotCfgChangeReporter() { 2306 if (!HTML) 2307 return; 2308 *HTML 2309 << "<script>var coll = document.getElementsByClassName(\"collapsible\");" 2310 << "var i;" 2311 << "for (i = 0; i < coll.length; i++) {" 2312 << "coll[i].addEventListener(\"click\", function() {" 2313 << " this.classList.toggle(\"active\");" 2314 << " var content = this.nextElementSibling;" 2315 << " if (content.style.display === \"block\"){" 2316 << " content.style.display = \"none\";" 2317 << " }" 2318 << " else {" 2319 << " content.style.display= \"block\";" 2320 << " }" 2321 << " });" 2322 << " }" 2323 << "</script>" 2324 << "</body>" 2325 << "</html>\n"; 2326 HTML->flush(); 2327 HTML->close(); 2328 } 2329 2330 void DotCfgChangeReporter::registerCallbacks( 2331 PassInstrumentationCallbacks &PIC) { 2332 if (PrintChanged == ChangePrinter::DotCfgVerbose || 2333 PrintChanged == ChangePrinter::DotCfgQuiet) { 2334 SmallString<128> OutputDir; 2335 sys::fs::expand_tilde(DotCfgDir, OutputDir); 2336 sys::fs::make_absolute(OutputDir); 2337 assert(!OutputDir.empty() && "expected output dir to be non-empty"); 2338 DotCfgDir = OutputDir.c_str(); 2339 if (initializeHTML()) { 2340 ChangeReporter<IRDataT<DCData>>::registerRequiredCallbacks(PIC); 2341 return; 2342 } 2343 dbgs() << "Unable to open output stream for -cfg-dot-changed\n"; 2344 } 2345 } 2346 2347 StandardInstrumentations::StandardInstrumentations( 2348 LLVMContext &Context, bool DebugLogging, bool VerifyEach, 2349 PrintPassOptions PrintPassOpts) 2350 : PrintPass(DebugLogging, PrintPassOpts), 2351 OptNone(DebugLogging), 2352 OptPassGate(Context), 2353 PrintChangedIR(PrintChanged == ChangePrinter::Verbose), 2354 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose || 2355 PrintChanged == ChangePrinter::ColourDiffVerbose, 2356 PrintChanged == ChangePrinter::ColourDiffVerbose || 2357 PrintChanged == ChangePrinter::ColourDiffQuiet), 2358 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose), 2359 Verify(DebugLogging), VerifyEach(VerifyEach) {} 2360 2361 PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter = 2362 nullptr; 2363 2364 void PrintCrashIRInstrumentation::reportCrashIR() { 2365 if (!PrintOnCrashPath.empty()) { 2366 std::error_code EC; 2367 raw_fd_ostream Out(PrintOnCrashPath, EC); 2368 if (EC) 2369 report_fatal_error(errorCodeToError(EC)); 2370 Out << SavedIR; 2371 } else { 2372 dbgs() << SavedIR; 2373 } 2374 } 2375 2376 void PrintCrashIRInstrumentation::SignalHandler(void *) { 2377 // Called by signal handlers so do not lock here 2378 // Is the PrintCrashIRInstrumentation still alive? 2379 if (!CrashReporter) 2380 return; 2381 2382 assert((PrintOnCrash || !PrintOnCrashPath.empty()) && 2383 "Did not expect to get here without option set."); 2384 CrashReporter->reportCrashIR(); 2385 } 2386 2387 PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() { 2388 if (!CrashReporter) 2389 return; 2390 2391 assert((PrintOnCrash || !PrintOnCrashPath.empty()) && 2392 "Did not expect to get here without option set."); 2393 CrashReporter = nullptr; 2394 } 2395 2396 void PrintCrashIRInstrumentation::registerCallbacks( 2397 PassInstrumentationCallbacks &PIC) { 2398 if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter) 2399 return; 2400 2401 sys::AddSignalHandler(SignalHandler, nullptr); 2402 CrashReporter = this; 2403 2404 PIC.registerBeforeNonSkippedPassCallback( 2405 [&PIC, this](StringRef PassID, Any IR) { 2406 SavedIR.clear(); 2407 raw_string_ostream OS(SavedIR); 2408 OS << formatv("*** Dump of {0}IR Before Last Pass {1}", 2409 llvm::forcePrintModuleIR() ? "Module " : "", PassID); 2410 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) { 2411 OS << " Filtered Out ***\n"; 2412 return; 2413 } 2414 OS << " Started ***\n"; 2415 unwrapAndPrint(OS, IR); 2416 }); 2417 } 2418 2419 void StandardInstrumentations::registerCallbacks( 2420 PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) { 2421 PrintIR.registerCallbacks(PIC); 2422 PrintPass.registerCallbacks(PIC); 2423 TimePasses.registerCallbacks(PIC); 2424 OptNone.registerCallbacks(PIC); 2425 OptPassGate.registerCallbacks(PIC); 2426 PrintChangedIR.registerCallbacks(PIC); 2427 PseudoProbeVerification.registerCallbacks(PIC); 2428 if (VerifyEach) 2429 Verify.registerCallbacks(PIC); 2430 PrintChangedDiff.registerCallbacks(PIC); 2431 WebsiteChangeReporter.registerCallbacks(PIC); 2432 ChangeTester.registerCallbacks(PIC); 2433 PrintCrashIR.registerCallbacks(PIC); 2434 if (MAM) 2435 PreservedCFGChecker.registerCallbacks(PIC, *MAM); 2436 2437 // TimeProfiling records the pass running time cost. 2438 // Its 'BeforePassCallback' can be appended at the tail of all the 2439 // BeforeCallbacks by calling `registerCallbacks` in the end. 2440 // Its 'AfterPassCallback' is put at the front of all the 2441 // AfterCallbacks by its `registerCallbacks`. This is necessary 2442 // to ensure that other callbacks are not included in the timings. 2443 TimeProfilingPasses.registerCallbacks(PIC); 2444 } 2445 2446 template class ChangeReporter<std::string>; 2447 template class TextChangeReporter<std::string>; 2448 2449 template class BlockDataT<EmptyData>; 2450 template class FuncDataT<EmptyData>; 2451 template class IRDataT<EmptyData>; 2452 template class ChangeReporter<IRDataT<EmptyData>>; 2453 template class TextChangeReporter<IRDataT<EmptyData>>; 2454 template class IRComparer<EmptyData>; 2455 2456 } // namespace llvm 2457