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