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