xref: /netbsd-src/external/apache2/llvm/dist/llvm/include/llvm/Passes/StandardInstrumentations.h (revision 82d56013d7b633d116a93943de88e08335357a7c)
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   bool StoreModuleDesc = false;
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 OptBisectInstrumentation {
78 public:
OptBisectInstrumentation()79   OptBisectInstrumentation() {}
80   void registerCallbacks(PassInstrumentationCallbacks &PIC);
81 };
82 
83 struct PrintPassOptions {
84   /// Print adaptors and pass managers.
85   bool Verbose = false;
86   /// Don't print information for analyses.
87   bool SkipAnalyses = false;
88   /// Indent based on hierarchy.
89   bool Indent = false;
90 };
91 
92 // Debug logging for transformation and analysis passes.
93 class PrintPassInstrumentation {
94   raw_ostream &print();
95 
96 public:
PrintPassInstrumentation(bool Enabled,PrintPassOptions Opts)97   PrintPassInstrumentation(bool Enabled, PrintPassOptions Opts)
98       : Enabled(Enabled), Opts(Opts) {}
99   void registerCallbacks(PassInstrumentationCallbacks &PIC);
100 
101 private:
102   bool Enabled;
103   PrintPassOptions Opts;
104   int Indent = 0;
105 };
106 
107 class PreservedCFGCheckerInstrumentation {
108 public:
109   // Keeps sticky poisoned flag for the given basic block once it has been
110   // deleted or RAUWed.
111   struct BBGuard final : public CallbackVH {
BBGuardfinal112     BBGuard(const BasicBlock *BB) : CallbackVH(BB) {}
deletedfinal113     void deleted() override { CallbackVH::deleted(); }
allUsesReplacedWithfinal114     void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); }
isPoisonedfinal115     bool isPoisoned() const { return !getValPtr(); }
116   };
117 
118   // CFG is a map BB -> {(Succ, Multiplicity)}, where BB is a non-leaf basic
119   // block, {(Succ, Multiplicity)} set of all pairs of the block's successors
120   // and the multiplicity of the edge (BB->Succ). As the mapped sets are
121   // unordered the order of successors is not tracked by the CFG. In other words
122   // this allows basic block successors to be swapped by a pass without
123   // reporting a CFG change. CFG can be guarded by basic block tracking pointers
124   // in the Graph (BBGuard). That is if any of the block is deleted or RAUWed
125   // then the CFG is treated poisoned and no block pointer of the Graph is used.
126   struct CFG {
127     Optional<DenseMap<intptr_t, BBGuard>> BBGuards;
128     DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph;
129 
130     CFG(const Function *F, bool TrackBBLifetime);
131 
132     bool operator==(const CFG &G) const {
133       return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph;
134     }
135 
isPoisonedCFG136     bool isPoisoned() const {
137       return BBGuards &&
138              std::any_of(BBGuards->begin(), BBGuards->end(),
139                          [](const auto &BB) { return BB.second.isPoisoned(); });
140     }
141 
142     static void printDiff(raw_ostream &out, const CFG &Before,
143                           const CFG &After);
144     bool invalidate(Function &F, const PreservedAnalyses &PA,
145                     FunctionAnalysisManager::Invalidator &);
146   };
147 
148 #ifndef NDEBUG
149   SmallVector<StringRef, 8> PassStack;
150 #endif
151 
152   static cl::opt<bool> VerifyPreservedCFG;
153   void registerCallbacks(PassInstrumentationCallbacks &PIC,
154                          FunctionAnalysisManager &FAM);
155 };
156 
157 // Base class for classes that report changes to the IR.
158 // It presents an interface for such classes and provides calls
159 // on various events as the new pass manager transforms the IR.
160 // It also provides filtering of information based on hidden options
161 // specifying which functions are interesting.
162 // Calls are made for the following events/queries:
163 // 1.  The initial IR processed.
164 // 2.  To get the representation of the IR (of type \p T).
165 // 3.  When a pass does not change the IR.
166 // 4.  When a pass changes the IR (given both before and after representations
167 //         of type \p T).
168 // 5.  When an IR is invalidated.
169 // 6.  When a pass is run on an IR that is not interesting (based on options).
170 // 7.  When a pass is ignored (pass manager or adapter pass).
171 // 8.  To compare two IR representations (of type \p T).
172 template <typename IRUnitT> class ChangeReporter {
173 protected:
ChangeReporter(bool RunInVerboseMode)174   ChangeReporter(bool RunInVerboseMode) : VerboseMode(RunInVerboseMode) {}
175 
176 public:
177   virtual ~ChangeReporter();
178 
179   // Determine if this pass/IR is interesting and if so, save the IR
180   // otherwise it is left on the stack without data.
181   void saveIRBeforePass(Any IR, StringRef PassID);
182   // Compare the IR from before the pass after the pass.
183   void handleIRAfterPass(Any IR, StringRef PassID);
184   // Handle the situation where a pass is invalidated.
185   void handleInvalidatedPass(StringRef PassID);
186 
187 protected:
188   // Register required callbacks.
189   void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC);
190 
191   // Return true when this is a defined function for which printing
192   // of changes is desired.
193   bool isInterestingFunction(const Function &F);
194 
195   // Return true when this is a pass for which printing of changes is desired.
196   bool isInterestingPass(StringRef PassID);
197 
198   // Return true when this is a pass on IR for which printing
199   // of changes is desired.
200   bool isInteresting(Any IR, StringRef PassID);
201 
202   // Called on the first IR processed.
203   virtual void handleInitialIR(Any IR) = 0;
204   // Called before and after a pass to get the representation of the IR.
205   virtual void generateIRRepresentation(Any IR, StringRef PassID,
206                                         IRUnitT &Output) = 0;
207   // Called when the pass is not iteresting.
208   virtual void omitAfter(StringRef PassID, std::string &Name) = 0;
209   // Called when an interesting IR has changed.
210   virtual void handleAfter(StringRef PassID, std::string &Name,
211                            const IRUnitT &Before, const IRUnitT &After,
212                            Any) = 0;
213   // Called when an interesting pass is invalidated.
214   virtual void handleInvalidated(StringRef PassID) = 0;
215   // Called when the IR or pass is not interesting.
216   virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
217   // Called when an ignored pass is encountered.
218   virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
219   // Called to compare the before and after representations of the IR.
220   virtual bool same(const IRUnitT &Before, const IRUnitT &After) = 0;
221 
222   // Stack of IRs before passes.
223   std::vector<IRUnitT> BeforeStack;
224   // Is this the first IR seen?
225   bool InitialIR = true;
226 
227   // Run in verbose mode, printing everything?
228   const bool VerboseMode;
229 };
230 
231 // An abstract template base class that handles printing banners and
232 // reporting when things have not changed or are filtered out.
233 template <typename IRUnitT>
234 class TextChangeReporter : public ChangeReporter<IRUnitT> {
235 protected:
236   TextChangeReporter(bool Verbose);
237 
238   // Print a module dump of the first IR that is changed.
239   void handleInitialIR(Any IR) override;
240   // Report that the IR was omitted because it did not change.
241   void omitAfter(StringRef PassID, std::string &Name) override;
242   // Report that the pass was invalidated.
243   void handleInvalidated(StringRef PassID) override;
244   // Report that the IR was filtered out.
245   void handleFiltered(StringRef PassID, std::string &Name) override;
246   // Report that the pass was ignored.
247   void handleIgnored(StringRef PassID, std::string &Name) override;
248   // Make substitutions in \p S suitable for reporting changes
249   // after the pass and then print it.
250 
251   raw_ostream &Out;
252 };
253 
254 // A change printer based on the string representation of the IR as created
255 // by unwrapAndPrint.  The string representation is stored in a std::string
256 // to preserve it as the IR changes in each pass.  Note that the banner is
257 // included in this representation but it is massaged before reporting.
258 class IRChangedPrinter : public TextChangeReporter<std::string> {
259 public:
IRChangedPrinter(bool VerboseMode)260   IRChangedPrinter(bool VerboseMode)
261       : TextChangeReporter<std::string>(VerboseMode) {}
262   ~IRChangedPrinter() override;
263   void registerCallbacks(PassInstrumentationCallbacks &PIC);
264 
265 protected:
266   // Called before and after a pass to get the representation of the IR.
267   void generateIRRepresentation(Any IR, StringRef PassID,
268                                 std::string &Output) override;
269   // Called when an interesting IR has changed.
270   void handleAfter(StringRef PassID, std::string &Name,
271                    const std::string &Before, const std::string &After,
272                    Any) override;
273   // Called to compare the before and after representations of the IR.
274   bool same(const std::string &Before, const std::string &After) override;
275 };
276 
277 // The following classes hold a representation of the IR for a change
278 // reporter that uses string comparisons of the basic blocks
279 // that are created using print (ie, similar to dump()).
280 // These classes respect the filtering of passes and functions using
281 // -filter-passes and -filter-print-funcs.
282 //
283 // Information that needs to be saved for a basic block in order to compare
284 // before and after the pass to determine if it was changed by a pass.
285 class ChangedBlockData {
286 public:
287   ChangedBlockData(const BasicBlock &B);
288 
289   bool operator==(const ChangedBlockData &That) const {
290     return Body == That.Body;
291   }
292   bool operator!=(const ChangedBlockData &That) const {
293     return Body != That.Body;
294   }
295 
296   // Return the label of the represented basic block.
getLabel()297   StringRef getLabel() const { return Label; }
298   // Return the string representation of the basic block.
getBody()299   StringRef getBody() const { return Body; }
300 
301 protected:
302   std::string Label;
303   std::string Body;
304 };
305 
306 template <typename IRData> class OrderedChangedData {
307 public:
308   // Return the names in the order they were saved
getOrder()309   std::vector<std::string> &getOrder() { return Order; }
getOrder()310   const std::vector<std::string> &getOrder() const { return Order; }
311 
312   // Return a map of names to saved representations
getData()313   StringMap<IRData> &getData() { return Data; }
getData()314   const StringMap<IRData> &getData() const { return Data; }
315 
316   bool operator==(const OrderedChangedData<IRData> &That) const {
317     return Data == That.getData();
318   }
319 
320   // Call the lambda \p HandlePair on each corresponding pair of data from
321   // \p Before and \p After.  The order is based on the order in \p After
322   // with ones that are only in \p Before interspersed based on where they
323   // occur in \p Before.  This is used to present the output in an order
324   // based on how the data is ordered in LLVM.
325   static void
326   report(const OrderedChangedData &Before, const OrderedChangedData &After,
327          function_ref<void(const IRData *, const IRData *)> HandlePair);
328 
329 protected:
330   std::vector<std::string> Order;
331   StringMap<IRData> Data;
332 };
333 
334 // The data saved for comparing functions.
335 using ChangedFuncData = OrderedChangedData<ChangedBlockData>;
336 
337 // A map of names to the saved data.
338 using ChangedIRData = OrderedChangedData<ChangedFuncData>;
339 
340 // A class that compares two IRs and does a diff between them.  The
341 // added lines are prefixed with a '+', the removed lines are prefixed
342 // with a '-' and unchanged lines are prefixed with a space (to have
343 // things line up).
344 class ChangedIRComparer {
345 public:
ChangedIRComparer(raw_ostream & OS,const ChangedIRData & Before,const ChangedIRData & After,bool ColourMode)346   ChangedIRComparer(raw_ostream &OS, const ChangedIRData &Before,
347                     const ChangedIRData &After, bool ColourMode)
348       : Before(Before), After(After), Out(OS), UseColour(ColourMode) {}
349 
350   // Compare the 2 IRs.
351   void compare(Any IR, StringRef Prefix, StringRef PassID, StringRef Name);
352 
353   // Analyze \p IR and build the IR representation in \p Data.
354   static void analyzeIR(Any IR, ChangedIRData &Data);
355 
356 protected:
357   // Return the module when that is the appropriate level of
358   // comparison for \p IR.
359   static const Module *getModuleForComparison(Any IR);
360 
361   // Generate the data for \p F into \p Data.
362   static bool generateFunctionData(ChangedIRData &Data, const Function &F);
363 
364   // Called to handle the compare of a function. When \p InModule is set,
365   // this function is being handled as part of comparing a module.
366   void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
367                              bool InModule, const ChangedFuncData &Before,
368                              const ChangedFuncData &After);
369 
370   const ChangedIRData &Before;
371   const ChangedIRData &After;
372   raw_ostream &Out;
373   bool UseColour;
374 };
375 
376 // A change printer that prints out in-line differences in the basic
377 // blocks.  It uses an InlineComparer to do the comparison so it shows
378 // the differences prefixed with '-' and '+' for code that is removed
379 // and added, respectively.  Changes to the IR that do not affect basic
380 // blocks are not reported as having changed the IR.  The option
381 // -print-module-scope does not affect this change reporter.
382 class InLineChangePrinter : public TextChangeReporter<ChangedIRData> {
383 public:
InLineChangePrinter(bool VerboseMode,bool ColourMode)384   InLineChangePrinter(bool VerboseMode, bool ColourMode)
385       : TextChangeReporter<ChangedIRData>(VerboseMode), UseColour(ColourMode) {}
386   ~InLineChangePrinter() override;
387   void registerCallbacks(PassInstrumentationCallbacks &PIC);
388 
389 protected:
390   // Create a representation of the IR.
391   virtual void generateIRRepresentation(Any IR, StringRef PassID,
392                                         ChangedIRData &Output) override;
393 
394   // Called when an interesting IR has changed.
395   virtual void handleAfter(StringRef PassID, std::string &Name,
396                            const ChangedIRData &Before,
397                            const ChangedIRData &After, Any) override;
398   // Called to compare the before and after representations of the IR.
399   virtual bool same(const ChangedIRData &Before,
400                     const ChangedIRData &After) override;
401 
402   bool UseColour;
403 };
404 
405 class VerifyInstrumentation {
406   bool DebugLogging;
407 
408 public:
VerifyInstrumentation(bool DebugLogging)409   VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
410   void registerCallbacks(PassInstrumentationCallbacks &PIC);
411 };
412 
413 /// This class provides an interface to register all the standard pass
414 /// instrumentations and manages their state (if any).
415 class StandardInstrumentations {
416   PrintIRInstrumentation PrintIR;
417   PrintPassInstrumentation PrintPass;
418   TimePassesHandler TimePasses;
419   OptNoneInstrumentation OptNone;
420   OptBisectInstrumentation OptBisect;
421   PreservedCFGCheckerInstrumentation PreservedCFGChecker;
422   IRChangedPrinter PrintChangedIR;
423   PseudoProbeVerifier PseudoProbeVerification;
424   InLineChangePrinter PrintChangedDiff;
425   VerifyInstrumentation Verify;
426 
427   bool VerifyEach;
428 
429 public:
430   StandardInstrumentations(bool DebugLogging, bool VerifyEach = false,
431                            PrintPassOptions PrintPassOpts = PrintPassOptions());
432 
433   // Register all the standard instrumentation callbacks. If \p FAM is nullptr
434   // then PreservedCFGChecker is not enabled.
435   void registerCallbacks(PassInstrumentationCallbacks &PIC,
436                          FunctionAnalysisManager *FAM = nullptr);
437 
getTimePasses()438   TimePassesHandler &getTimePasses() { return TimePasses; }
439 };
440 
441 extern template class ChangeReporter<std::string>;
442 extern template class TextChangeReporter<std::string>;
443 
444 extern template class ChangeReporter<ChangedIRData>;
445 extern template class TextChangeReporter<ChangedIRData>;
446 
447 } // namespace llvm
448 
449 #endif
450