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