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