1 //===- StandardInstrumentations.h ------------------------------*- 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 header defines a class that provides bookkeeping for all standard 11 /// (i.e in-tree) pass instrumentations. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_PASSES_STANDARDINSTRUMENTATIONS_H 16 #define LLVM_PASSES_STANDARDINSTRUMENTATIONS_H 17 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/ADT/StringSet.h" 22 #include "llvm/CodeGen/MachineBasicBlock.h" 23 #include "llvm/IR/BasicBlock.h" 24 #include "llvm/IR/OptBisect.h" 25 #include "llvm/IR/PassTimingInfo.h" 26 #include "llvm/IR/ValueHandle.h" 27 #include "llvm/Support/CommandLine.h" 28 #include "llvm/Support/TimeProfiler.h" 29 #include "llvm/Transforms/IPO/SampleProfileProbe.h" 30 31 #include <string> 32 #include <utility> 33 34 namespace llvm { 35 36 class Module; 37 class Function; 38 class MachineFunction; 39 class PassInstrumentationCallbacks; 40 41 /// Instrumentation to print IR before/after passes. 42 /// 43 /// Needs state to be able to print module after pass that invalidates IR unit 44 /// (typically Loop or SCC). 45 class PrintIRInstrumentation { 46 public: 47 ~PrintIRInstrumentation(); 48 49 void registerCallbacks(PassInstrumentationCallbacks &PIC); 50 51 private: 52 struct PassRunDescriptor { 53 const Module *M; 54 const std::string DumpIRFilename; 55 const std::string IRName; 56 const StringRef PassID; 57 PassRunDescriptorPassRunDescriptor58 PassRunDescriptor(const Module *M, std::string DumpIRFilename, 59 std::string IRName, const StringRef PassID) 60 : M{M}, DumpIRFilename{DumpIRFilename}, IRName{IRName}, PassID(PassID) { 61 } 62 }; 63 64 void printBeforePass(StringRef PassID, Any IR); 65 void printAfterPass(StringRef PassID, Any IR); 66 void printAfterPassInvalidated(StringRef PassID); 67 68 bool shouldPrintBeforePass(StringRef PassID); 69 bool shouldPrintAfterPass(StringRef PassID); 70 bool shouldPrintBeforeCurrentPassNumber(); 71 bool shouldPrintAfterCurrentPassNumber(); 72 bool shouldPrintPassNumbers(); 73 bool shouldPrintBeforeSomePassNumber(); 74 bool shouldPrintAfterSomePassNumber(); 75 76 void pushPassRunDescriptor(StringRef PassID, Any IR, 77 std::string &DumpIRFilename); 78 PassRunDescriptor popPassRunDescriptor(StringRef PassID); 79 std::string fetchDumpFilename(StringRef PassId, Any IR); 80 81 PassInstrumentationCallbacks *PIC; 82 /// Stack of Pass Run descriptions, enough to print the IR unit after a given 83 /// pass. 84 SmallVector<PassRunDescriptor, 2> PassRunDescriptorStack; 85 86 /// Used for print-at-pass-number 87 unsigned CurrentPassNumber = 0; 88 }; 89 90 class OptNoneInstrumentation { 91 public: OptNoneInstrumentation(bool DebugLogging)92 OptNoneInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {} 93 void registerCallbacks(PassInstrumentationCallbacks &PIC); 94 95 private: 96 bool DebugLogging; 97 bool shouldRun(StringRef PassID, Any IR); 98 }; 99 100 class OptPassGateInstrumentation { 101 LLVMContext &Context; 102 bool HasWrittenIR = false; 103 public: OptPassGateInstrumentation(LLVMContext & Context)104 OptPassGateInstrumentation(LLVMContext &Context) : Context(Context) {} 105 bool shouldRun(StringRef PassName, Any IR); 106 void registerCallbacks(PassInstrumentationCallbacks &PIC); 107 }; 108 109 struct PrintPassOptions { 110 /// Print adaptors and pass managers. 111 bool Verbose = false; 112 /// Don't print information for analyses. 113 bool SkipAnalyses = false; 114 /// Indent based on hierarchy. 115 bool Indent = false; 116 }; 117 118 // Debug logging for transformation and analysis passes. 119 class PrintPassInstrumentation { 120 raw_ostream &print(); 121 122 public: PrintPassInstrumentation(bool Enabled,PrintPassOptions Opts)123 PrintPassInstrumentation(bool Enabled, PrintPassOptions Opts) 124 : Enabled(Enabled), Opts(Opts) {} 125 void registerCallbacks(PassInstrumentationCallbacks &PIC); 126 127 private: 128 bool Enabled; 129 PrintPassOptions Opts; 130 int Indent = 0; 131 }; 132 133 class PreservedCFGCheckerInstrumentation { 134 public: 135 // Keeps sticky poisoned flag for the given basic block once it has been 136 // deleted or RAUWed. 137 struct BBGuard final : public CallbackVH { BBGuardfinal138 BBGuard(const BasicBlock *BB) : CallbackVH(BB) {} deletedfinal139 void deleted() override { CallbackVH::deleted(); } allUsesReplacedWithfinal140 void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); } isPoisonedfinal141 bool isPoisoned() const { return !getValPtr(); } 142 }; 143 144 // CFG is a map BB -> {(Succ, Multiplicity)}, where BB is a non-leaf basic 145 // block, {(Succ, Multiplicity)} set of all pairs of the block's successors 146 // and the multiplicity of the edge (BB->Succ). As the mapped sets are 147 // unordered the order of successors is not tracked by the CFG. In other words 148 // this allows basic block successors to be swapped by a pass without 149 // reporting a CFG change. CFG can be guarded by basic block tracking pointers 150 // in the Graph (BBGuard). That is if any of the block is deleted or RAUWed 151 // then the CFG is treated poisoned and no block pointer of the Graph is used. 152 struct CFG { 153 std::optional<DenseMap<intptr_t, BBGuard>> BBGuards; 154 DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph; 155 156 CFG(const Function *F, bool TrackBBLifetime); 157 158 bool operator==(const CFG &G) const { 159 return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph; 160 } 161 isPoisonedCFG162 bool isPoisoned() const { 163 return BBGuards && llvm::any_of(*BBGuards, [](const auto &BB) { 164 return BB.second.isPoisoned(); 165 }); 166 } 167 168 static void printDiff(raw_ostream &out, const CFG &Before, 169 const CFG &After); 170 bool invalidate(Function &F, const PreservedAnalyses &PA, 171 FunctionAnalysisManager::Invalidator &); 172 }; 173 174 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS 175 SmallVector<StringRef, 8> PassStack; 176 #endif 177 178 void registerCallbacks(PassInstrumentationCallbacks &PIC, 179 ModuleAnalysisManager &MAM); 180 }; 181 182 // Base class for classes that report changes to the IR. 183 // It presents an interface for such classes and provides calls 184 // on various events as the new pass manager transforms the IR. 185 // It also provides filtering of information based on hidden options 186 // specifying which functions are interesting. 187 // Calls are made for the following events/queries: 188 // 1. The initial IR processed. 189 // 2. To get the representation of the IR (of type \p T). 190 // 3. When a pass does not change the IR. 191 // 4. When a pass changes the IR (given both before and after representations 192 // of type \p T). 193 // 5. When an IR is invalidated. 194 // 6. When a pass is run on an IR that is not interesting (based on options). 195 // 7. When a pass is ignored (pass manager or adapter pass). 196 // 8. To compare two IR representations (of type \p T). 197 template <typename IRUnitT> class ChangeReporter { 198 protected: ChangeReporter(bool RunInVerboseMode)199 ChangeReporter(bool RunInVerboseMode) : VerboseMode(RunInVerboseMode) {} 200 201 public: 202 virtual ~ChangeReporter(); 203 204 // Determine if this pass/IR is interesting and if so, save the IR 205 // otherwise it is left on the stack without data. 206 void saveIRBeforePass(Any IR, StringRef PassID, StringRef PassName); 207 // Compare the IR from before the pass after the pass. 208 void handleIRAfterPass(Any IR, StringRef PassID, StringRef PassName); 209 // Handle the situation where a pass is invalidated. 210 void handleInvalidatedPass(StringRef PassID); 211 212 protected: 213 // Register required callbacks. 214 void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC); 215 216 // Called on the first IR processed. 217 virtual void handleInitialIR(Any IR) = 0; 218 // Called before and after a pass to get the representation of the IR. 219 virtual void generateIRRepresentation(Any IR, StringRef PassID, 220 IRUnitT &Output) = 0; 221 // Called when the pass is not iteresting. 222 virtual void omitAfter(StringRef PassID, std::string &Name) = 0; 223 // Called when an interesting IR has changed. 224 virtual void handleAfter(StringRef PassID, std::string &Name, 225 const IRUnitT &Before, const IRUnitT &After, 226 Any) = 0; 227 // Called when an interesting pass is invalidated. 228 virtual void handleInvalidated(StringRef PassID) = 0; 229 // Called when the IR or pass is not interesting. 230 virtual void handleFiltered(StringRef PassID, std::string &Name) = 0; 231 // Called when an ignored pass is encountered. 232 virtual void handleIgnored(StringRef PassID, std::string &Name) = 0; 233 234 // Stack of IRs before passes. 235 std::vector<IRUnitT> BeforeStack; 236 // Is this the first IR seen? 237 bool InitialIR = true; 238 239 // Run in verbose mode, printing everything? 240 const bool VerboseMode; 241 }; 242 243 // An abstract template base class that handles printing banners and 244 // reporting when things have not changed or are filtered out. 245 template <typename IRUnitT> 246 class TextChangeReporter : public ChangeReporter<IRUnitT> { 247 protected: 248 TextChangeReporter(bool Verbose); 249 250 // Print a module dump of the first IR that is changed. 251 void handleInitialIR(Any IR) override; 252 // Report that the IR was omitted because it did not change. 253 void omitAfter(StringRef PassID, std::string &Name) override; 254 // Report that the pass was invalidated. 255 void handleInvalidated(StringRef PassID) override; 256 // Report that the IR was filtered out. 257 void handleFiltered(StringRef PassID, std::string &Name) override; 258 // Report that the pass was ignored. 259 void handleIgnored(StringRef PassID, std::string &Name) override; 260 // Make substitutions in \p S suitable for reporting changes 261 // after the pass and then print it. 262 263 raw_ostream &Out; 264 }; 265 266 // A change printer based on the string representation of the IR as created 267 // by unwrapAndPrint. The string representation is stored in a std::string 268 // to preserve it as the IR changes in each pass. Note that the banner is 269 // included in this representation but it is massaged before reporting. 270 class IRChangedPrinter : public TextChangeReporter<std::string> { 271 public: IRChangedPrinter(bool VerboseMode)272 IRChangedPrinter(bool VerboseMode) 273 : TextChangeReporter<std::string>(VerboseMode) {} 274 ~IRChangedPrinter() override; 275 void registerCallbacks(PassInstrumentationCallbacks &PIC); 276 277 protected: 278 // Called before and after a pass to get the representation of the IR. 279 void generateIRRepresentation(Any IR, StringRef PassID, 280 std::string &Output) override; 281 // Called when an interesting IR has changed. 282 void handleAfter(StringRef PassID, std::string &Name, 283 const std::string &Before, const std::string &After, 284 Any) override; 285 }; 286 287 class IRChangedTester : public IRChangedPrinter { 288 public: IRChangedTester()289 IRChangedTester() : IRChangedPrinter(true) {} 290 ~IRChangedTester() override; 291 void registerCallbacks(PassInstrumentationCallbacks &PIC); 292 293 protected: 294 void handleIR(const std::string &IR, StringRef PassID); 295 296 // Check initial IR 297 void handleInitialIR(Any IR) override; 298 // Do nothing. 299 void omitAfter(StringRef PassID, std::string &Name) override; 300 // Do nothing. 301 void handleInvalidated(StringRef PassID) override; 302 // Do nothing. 303 void handleFiltered(StringRef PassID, std::string &Name) override; 304 // Do nothing. 305 void handleIgnored(StringRef PassID, std::string &Name) override; 306 307 // Call test as interesting IR has changed. 308 void handleAfter(StringRef PassID, std::string &Name, 309 const std::string &Before, const std::string &After, 310 Any) override; 311 }; 312 313 // Information that needs to be saved for a basic block in order to compare 314 // before and after the pass to determine if it was changed by a pass. 315 template <typename T> class BlockDataT { 316 public: BlockDataT(const BasicBlock & B)317 BlockDataT(const BasicBlock &B) : Label(B.getName().str()), Data(B) { 318 raw_string_ostream SS(Body); 319 B.print(SS, nullptr, true, true); 320 } 321 BlockDataT(const MachineBasicBlock & B)322 BlockDataT(const MachineBasicBlock &B) : Label(B.getName().str()), Data(B) { 323 raw_string_ostream SS(Body); 324 B.print(SS); 325 } 326 327 bool operator==(const BlockDataT &That) const { return Body == That.Body; } 328 bool operator!=(const BlockDataT &That) const { return Body != That.Body; } 329 330 // Return the label of the represented basic block. getLabel()331 StringRef getLabel() const { return Label; } 332 // Return the string representation of the basic block. getBody()333 StringRef getBody() const { return Body; } 334 335 // Return the associated data getData()336 const T &getData() const { return Data; } 337 338 protected: 339 std::string Label; 340 std::string Body; 341 342 // Extra data associated with a basic block 343 T Data; 344 }; 345 346 template <typename T> class OrderedChangedData { 347 public: 348 // Return the names in the order they were saved getOrder()349 std::vector<std::string> &getOrder() { return Order; } getOrder()350 const std::vector<std::string> &getOrder() const { return Order; } 351 352 // Return a map of names to saved representations getData()353 StringMap<T> &getData() { return Data; } getData()354 const StringMap<T> &getData() const { return Data; } 355 356 bool operator==(const OrderedChangedData<T> &That) const { 357 return Data == That.getData(); 358 } 359 360 // Call the lambda \p HandlePair on each corresponding pair of data from 361 // \p Before and \p After. The order is based on the order in \p After 362 // with ones that are only in \p Before interspersed based on where they 363 // occur in \p Before. This is used to present the output in an order 364 // based on how the data is ordered in LLVM. 365 static void report(const OrderedChangedData &Before, 366 const OrderedChangedData &After, 367 function_ref<void(const T *, const T *)> HandlePair); 368 369 protected: 370 std::vector<std::string> Order; 371 StringMap<T> Data; 372 }; 373 374 // Do not need extra information for patch-style change reporter. 375 class EmptyData { 376 public: EmptyData(const BasicBlock &)377 EmptyData(const BasicBlock &) {} EmptyData(const MachineBasicBlock &)378 EmptyData(const MachineBasicBlock &) {} 379 }; 380 381 // The data saved for comparing functions. 382 template <typename T> 383 class FuncDataT : public OrderedChangedData<BlockDataT<T>> { 384 public: FuncDataT(std::string S)385 FuncDataT(std::string S) : EntryBlockName(S) {} 386 387 // Return the name of the entry block getEntryBlockName()388 std::string getEntryBlockName() const { return EntryBlockName; } 389 390 protected: 391 std::string EntryBlockName; 392 }; 393 394 // The data saved for comparing IRs. 395 template <typename T> 396 class IRDataT : public OrderedChangedData<FuncDataT<T>> {}; 397 398 // Abstract template base class for a class that compares two IRs. The 399 // class is created with the 2 IRs to compare and then compare is called. 400 // The static function analyzeIR is used to build up the IR representation. 401 template <typename T> class IRComparer { 402 public: IRComparer(const IRDataT<T> & Before,const IRDataT<T> & After)403 IRComparer(const IRDataT<T> &Before, const IRDataT<T> &After) 404 : Before(Before), After(After) {} 405 406 // Compare the 2 IRs. \p handleFunctionCompare is called to handle the 407 // compare of a function. When \p InModule is set, 408 // this function is being handled as part of comparing a module. 409 void compare( 410 bool CompareModule, 411 std::function<void(bool InModule, unsigned Minor, 412 const FuncDataT<T> &Before, const FuncDataT<T> &After)> 413 CompareFunc); 414 415 // Analyze \p IR and build the IR representation in \p Data. 416 static void analyzeIR(Any IR, IRDataT<T> &Data); 417 418 protected: 419 // Generate the data for \p F into \p Data. 420 template <typename FunctionT> 421 static bool generateFunctionData(IRDataT<T> &Data, const FunctionT &F); 422 423 const IRDataT<T> &Before; 424 const IRDataT<T> &After; 425 }; 426 427 // A change printer that prints out in-line differences in the basic 428 // blocks. It uses an InlineComparer to do the comparison so it shows 429 // the differences prefixed with '-' and '+' for code that is removed 430 // and added, respectively. Changes to the IR that do not affect basic 431 // blocks are not reported as having changed the IR. The option 432 // -print-module-scope does not affect this change reporter. 433 class InLineChangePrinter : public TextChangeReporter<IRDataT<EmptyData>> { 434 public: InLineChangePrinter(bool VerboseMode,bool ColourMode)435 InLineChangePrinter(bool VerboseMode, bool ColourMode) 436 : TextChangeReporter<IRDataT<EmptyData>>(VerboseMode), 437 UseColour(ColourMode) {} 438 ~InLineChangePrinter() override; 439 void registerCallbacks(PassInstrumentationCallbacks &PIC); 440 441 protected: 442 // Create a representation of the IR. 443 void generateIRRepresentation(Any IR, StringRef PassID, 444 IRDataT<EmptyData> &Output) override; 445 446 // Called when an interesting IR has changed. 447 void handleAfter(StringRef PassID, std::string &Name, 448 const IRDataT<EmptyData> &Before, 449 const IRDataT<EmptyData> &After, Any) override; 450 451 void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, 452 StringRef Divider, bool InModule, unsigned Minor, 453 const FuncDataT<EmptyData> &Before, 454 const FuncDataT<EmptyData> &After); 455 456 bool UseColour; 457 }; 458 459 class VerifyInstrumentation { 460 bool DebugLogging; 461 462 public: VerifyInstrumentation(bool DebugLogging)463 VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {} 464 void registerCallbacks(PassInstrumentationCallbacks &PIC); 465 }; 466 467 /// This class implements --time-trace functionality for new pass manager. 468 /// It provides the pass-instrumentation callbacks that measure the pass 469 /// execution time. They collect time tracing info by TimeProfiler. 470 class TimeProfilingPassesHandler { 471 public: 472 TimeProfilingPassesHandler(); 473 // We intend this to be unique per-compilation, thus no copies. 474 TimeProfilingPassesHandler(const TimeProfilingPassesHandler &) = delete; 475 void operator=(const TimeProfilingPassesHandler &) = delete; 476 477 void registerCallbacks(PassInstrumentationCallbacks &PIC); 478 479 private: 480 // Implementation of pass instrumentation callbacks. 481 void runBeforePass(StringRef PassID, Any IR); 482 void runAfterPass(); 483 }; 484 485 // Class that holds transitions between basic blocks. The transitions 486 // are contained in a map of values to names of basic blocks. 487 class DCData { 488 public: 489 // Fill the map with the transitions from basic block \p B. 490 DCData(const BasicBlock &B); 491 DCData(const MachineBasicBlock &B); 492 493 // Return an iterator to the names of the successor blocks. begin()494 StringMap<std::string>::const_iterator begin() const { 495 return Successors.begin(); 496 } end()497 StringMap<std::string>::const_iterator end() const { 498 return Successors.end(); 499 } 500 501 // Return the label of the basic block reached on a transition on \p S. getSuccessorLabel(StringRef S)502 StringRef getSuccessorLabel(StringRef S) const { 503 assert(Successors.count(S) == 1 && "Expected to find successor."); 504 return Successors.find(S)->getValue(); 505 } 506 507 protected: 508 // Add a transition to \p Succ on \p Label addSuccessorLabel(StringRef Succ,StringRef Label)509 void addSuccessorLabel(StringRef Succ, StringRef Label) { 510 std::pair<std::string, std::string> SS{Succ.str(), Label.str()}; 511 Successors.insert(SS); 512 } 513 514 StringMap<std::string> Successors; 515 }; 516 517 // A change reporter that builds a website with links to pdf files showing 518 // dot control flow graphs with changed instructions shown in colour. 519 class DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> { 520 public: 521 DotCfgChangeReporter(bool Verbose); 522 ~DotCfgChangeReporter() override; 523 void registerCallbacks(PassInstrumentationCallbacks &PIC); 524 525 protected: 526 // Initialize the HTML file and output the header. 527 bool initializeHTML(); 528 529 // Called on the first IR processed. 530 void handleInitialIR(Any IR) override; 531 // Called before and after a pass to get the representation of the IR. 532 void generateIRRepresentation(Any IR, StringRef PassID, 533 IRDataT<DCData> &Output) override; 534 // Called when the pass is not iteresting. 535 void omitAfter(StringRef PassID, std::string &Name) override; 536 // Called when an interesting IR has changed. 537 void handleAfter(StringRef PassID, std::string &Name, 538 const IRDataT<DCData> &Before, const IRDataT<DCData> &After, 539 Any) override; 540 // Called when an interesting pass is invalidated. 541 void handleInvalidated(StringRef PassID) override; 542 // Called when the IR or pass is not interesting. 543 void handleFiltered(StringRef PassID, std::string &Name) override; 544 // Called when an ignored pass is encountered. 545 void handleIgnored(StringRef PassID, std::string &Name) override; 546 547 // Generate the pdf file into \p Dir / \p PDFFileName using \p DotFile as 548 // input and return the html <a> tag with \Text as the content. 549 static std::string genHTML(StringRef Text, StringRef DotFile, 550 StringRef PDFFileName); 551 552 void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, 553 StringRef Divider, bool InModule, unsigned Minor, 554 const FuncDataT<DCData> &Before, 555 const FuncDataT<DCData> &After); 556 557 unsigned N = 0; 558 std::unique_ptr<raw_fd_ostream> HTML; 559 }; 560 561 // Print IR on crash. 562 class PrintCrashIRInstrumentation { 563 public: PrintCrashIRInstrumentation()564 PrintCrashIRInstrumentation() 565 : SavedIR("*** Dump of IR Before Last Pass Unknown ***") {} 566 ~PrintCrashIRInstrumentation(); 567 void registerCallbacks(PassInstrumentationCallbacks &PIC); 568 void reportCrashIR(); 569 570 protected: 571 std::string SavedIR; 572 573 private: 574 // The crash reporter that will report on a crash. 575 static PrintCrashIRInstrumentation *CrashReporter; 576 // Crash handler registered when print-on-crash is specified. 577 static void SignalHandler(void *); 578 }; 579 580 /// This class provides an interface to register all the standard pass 581 /// instrumentations and manages their state (if any). 582 class StandardInstrumentations { 583 PrintIRInstrumentation PrintIR; 584 PrintPassInstrumentation PrintPass; 585 TimePassesHandler TimePasses; 586 TimeProfilingPassesHandler TimeProfilingPasses; 587 OptNoneInstrumentation OptNone; 588 OptPassGateInstrumentation OptPassGate; 589 PreservedCFGCheckerInstrumentation PreservedCFGChecker; 590 IRChangedPrinter PrintChangedIR; 591 PseudoProbeVerifier PseudoProbeVerification; 592 InLineChangePrinter PrintChangedDiff; 593 DotCfgChangeReporter WebsiteChangeReporter; 594 PrintCrashIRInstrumentation PrintCrashIR; 595 IRChangedTester ChangeTester; 596 VerifyInstrumentation Verify; 597 598 bool VerifyEach; 599 600 public: 601 StandardInstrumentations(LLVMContext &Context, bool DebugLogging, 602 bool VerifyEach = false, 603 PrintPassOptions PrintPassOpts = PrintPassOptions()); 604 605 // Register all the standard instrumentation callbacks. If \p FAM is nullptr 606 // then PreservedCFGChecker is not enabled. 607 void registerCallbacks(PassInstrumentationCallbacks &PIC, 608 ModuleAnalysisManager *MAM = nullptr); 609 getTimePasses()610 TimePassesHandler &getTimePasses() { return TimePasses; } 611 }; 612 613 extern template class ChangeReporter<std::string>; 614 extern template class TextChangeReporter<std::string>; 615 616 extern template class BlockDataT<EmptyData>; 617 extern template class FuncDataT<EmptyData>; 618 extern template class IRDataT<EmptyData>; 619 extern template class ChangeReporter<IRDataT<EmptyData>>; 620 extern template class TextChangeReporter<IRDataT<EmptyData>>; 621 extern template class IRComparer<EmptyData>; 622 623 } // namespace llvm 624 625 #endif 626