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