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