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