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