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/SmallVector.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/IR/BasicBlock.h"
21 #include "llvm/IR/OptBisect.h"
22 #include "llvm/IR/PassTimingInfo.h"
23 #include "llvm/IR/ValueHandle.h"
24 #include "llvm/Support/CommandLine.h"
25 
26 #include <string>
27 #include <utility>
28 
29 namespace llvm {
30 
31 class Module;
32 class Function;
33 class PassInstrumentationCallbacks;
34 
35 /// Instrumentation to print IR before/after passes.
36 ///
37 /// Needs state to be able to print module after pass that invalidates IR unit
38 /// (typically Loop or SCC).
39 class PrintIRInstrumentation {
40 public:
41   ~PrintIRInstrumentation();
42 
43   void registerCallbacks(PassInstrumentationCallbacks &PIC);
44 
45 private:
46   void printBeforePass(StringRef PassID, Any IR);
47   void printAfterPass(StringRef PassID, Any IR);
48   void printAfterPassInvalidated(StringRef PassID);
49 
50   bool shouldPrintBeforePass(StringRef PassID);
51   bool shouldPrintAfterPass(StringRef PassID);
52 
53   using PrintModuleDesc = std::tuple<const Module *, std::string, StringRef>;
54 
55   void pushModuleDesc(StringRef PassID, Any IR);
56   PrintModuleDesc popModuleDesc(StringRef PassID);
57 
58   PassInstrumentationCallbacks *PIC;
59   /// Stack of Module description, enough to print the module after a given
60   /// pass.
61   SmallVector<PrintModuleDesc, 2> ModuleDescStack;
62   bool StoreModuleDesc = false;
63 };
64 
65 class OptNoneInstrumentation {
66 public:
OptNoneInstrumentation(bool DebugLogging)67   OptNoneInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
68   void registerCallbacks(PassInstrumentationCallbacks &PIC);
69 
70 private:
71   bool DebugLogging;
72   bool shouldRun(StringRef PassID, Any IR);
73 };
74 
75 class OptBisectInstrumentation : public OptBisect {
76 public:
OptBisectInstrumentation()77   OptBisectInstrumentation() {}
78   void registerCallbacks(PassInstrumentationCallbacks &PIC);
79 };
80 
81 // Debug logging for transformation and analysis passes.
82 class PrintPassInstrumentation {
83 public:
PrintPassInstrumentation(bool DebugLogging)84   PrintPassInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
85   void registerCallbacks(PassInstrumentationCallbacks &PIC);
86 
87 private:
88   bool DebugLogging;
89 };
90 
91 class PreservedCFGCheckerInstrumentation {
92 private:
93   // CFG is a map BB -> {(Succ, Multiplicity)}, where BB is a non-leaf basic
94   // block, {(Succ, Multiplicity)} set of all pairs of the block's successors
95   // and the multiplicity of the edge (BB->Succ). As the mapped sets are
96   // unordered the order of successors is not tracked by the CFG. In other words
97   // this allows basic block successors to be swapped by a pass without
98   // reporting a CFG change. CFG can be guarded by basic block tracking pointers
99   // in the Graph (BBGuard). That is if any of the block is deleted or RAUWed
100   // then the CFG is treated poisoned and no block pointer of the Graph is used.
101   struct CFG {
102     struct BBGuard final : public CallbackVH {
BBGuardCFG::final103       BBGuard(const BasicBlock *BB) : CallbackVH(BB) {}
deletedCFG::final104       void deleted() override { CallbackVH::deleted(); }
allUsesReplacedWithCFG::final105       void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); }
isPoisonedCFG::final106       bool isPoisoned() const { return !getValPtr(); }
107     };
108 
109     Optional<DenseMap<intptr_t, BBGuard>> BBGuards;
110     DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph;
111 
112     CFG(const Function *F, bool TrackBBLifetime = false);
113 
114     bool operator==(const CFG &G) const {
115       return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph;
116     }
117 
isPoisonedCFG118     bool isPoisoned() const {
119       if (BBGuards)
120         for (auto &BB : *BBGuards) {
121           if (BB.second.isPoisoned())
122             return true;
123         }
124       return false;
125     }
126 
127     static void printDiff(raw_ostream &out, const CFG &Before,
128                           const CFG &After);
129   };
130 
131   SmallVector<std::pair<StringRef, Optional<CFG>>, 8> GraphStackBefore;
132 
133 public:
134   static cl::opt<bool> VerifyPreservedCFG;
135   void registerCallbacks(PassInstrumentationCallbacks &PIC);
136 };
137 
138 // Base class for classes that report changes to the IR.
139 // It presents an interface for such classes and provides calls
140 // on various events as the new pass manager transforms the IR.
141 // It also provides filtering of information based on hidden options
142 // specifying which functions are interesting.
143 // Calls are made for the following events/queries:
144 // 1.  The initial IR processed.
145 // 2.  To get the representation of the IR (of type \p T).
146 // 3.  When a pass does not change the IR.
147 // 4.  When a pass changes the IR (given both before and after representations
148 //         of type \p T).
149 // 5.  When an IR is invalidated.
150 // 6.  When a pass is run on an IR that is not interesting (based on options).
151 // 7.  When a pass is ignored (pass manager or adapter pass).
152 // 8.  To compare two IR representations (of type \p T).
153 template <typename IRUnitT> class ChangeReporter {
154 protected:
ChangeReporter()155   ChangeReporter() {}
156 
157 public:
158   virtual ~ChangeReporter();
159 
160   // Determine if this pass/IR is interesting and if so, save the IR
161   // otherwise it is left on the stack without data.
162   void saveIRBeforePass(Any IR, StringRef PassID);
163   // Compare the IR from before the pass after the pass.
164   void handleIRAfterPass(Any IR, StringRef PassID);
165   // Handle the situation where a pass is invalidated.
166   void handleInvalidatedPass(StringRef PassID);
167 
168 protected:
169   // Register required callbacks.
170   void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC);
171 
172   // Return true when this is a defined function for which printing
173   // of changes is desired.
174   bool isInterestingFunction(const Function &F);
175 
176   // Return true when this is a pass for which printing of changes is desired.
177   bool isInterestingPass(StringRef PassID);
178 
179   // Return true when this is a pass on IR for which printing
180   // of changes is desired.
181   bool isInteresting(Any IR, StringRef PassID);
182 
183   // Called on the first IR processed.
184   virtual void handleInitialIR(Any IR) = 0;
185   // Called before and after a pass to get the representation of the IR.
186   virtual void generateIRRepresentation(Any IR, StringRef PassID,
187                                         IRUnitT &Output) = 0;
188   // Called when the pass is not iteresting.
189   virtual void omitAfter(StringRef PassID, std::string &Name) = 0;
190   // Called when an interesting IR has changed.
191   virtual void handleAfter(StringRef PassID, std::string &Name,
192                            const IRUnitT &Before, const IRUnitT &After,
193                            Any) = 0;
194   // Called when an interesting pass is invalidated.
195   virtual void handleInvalidated(StringRef PassID) = 0;
196   // Called when the IR or pass is not interesting.
197   virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
198   // Called when an ignored pass is encountered.
199   virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
200   // Called to compare the before and after representations of the IR.
201   virtual bool same(const IRUnitT &Before, const IRUnitT &After) = 0;
202 
203   // Stack of IRs before passes.
204   std::vector<IRUnitT> BeforeStack;
205   // Is this the first IR seen?
206   bool InitialIR = true;
207 };
208 
209 // An abstract template base class that handles printing banners and
210 // reporting when things have not changed or are filtered out.
211 template <typename IRUnitT>
212 class TextChangeReporter : public ChangeReporter<IRUnitT> {
213 protected:
214   TextChangeReporter();
215 
216   // Print a module dump of the first IR that is changed.
217   void handleInitialIR(Any IR) override;
218   // Report that the IR was omitted because it did not change.
219   void omitAfter(StringRef PassID, std::string &Name) override;
220   // Report that the pass was invalidated.
221   void handleInvalidated(StringRef PassID) override;
222   // Report that the IR was filtered out.
223   void handleFiltered(StringRef PassID, std::string &Name) override;
224   // Report that the pass was ignored.
225   void handleIgnored(StringRef PassID, std::string &Name) override;
226   // Make substitutions in \p S suitable for reporting changes
227   // after the pass and then print it.
228 
229   raw_ostream &Out;
230 };
231 
232 // A change printer based on the string representation of the IR as created
233 // by unwrapAndPrint.  The string representation is stored in a std::string
234 // to preserve it as the IR changes in each pass.  Note that the banner is
235 // included in this representation but it is massaged before reporting.
236 class IRChangedPrinter : public TextChangeReporter<std::string> {
237 public:
IRChangedPrinter()238   IRChangedPrinter() {}
239   ~IRChangedPrinter() override;
240   void registerCallbacks(PassInstrumentationCallbacks &PIC);
241 
242 protected:
243   // Called before and after a pass to get the representation of the IR.
244   void generateIRRepresentation(Any IR, StringRef PassID,
245                                 std::string &Output) override;
246   // Called when an interesting IR has changed.
247   void handleAfter(StringRef PassID, std::string &Name,
248                    const std::string &Before, const std::string &After,
249                    Any) override;
250   // Called to compare the before and after representations of the IR.
251   bool same(const std::string &Before, const std::string &After) override;
252 };
253 
254 class VerifyInstrumentation {
255   bool DebugLogging;
256 
257 public:
VerifyInstrumentation(bool DebugLogging)258   VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
259   void registerCallbacks(PassInstrumentationCallbacks &PIC);
260 };
261 
262 /// This class provides an interface to register all the standard pass
263 /// instrumentations and manages their state (if any).
264 class StandardInstrumentations {
265   PrintIRInstrumentation PrintIR;
266   PrintPassInstrumentation PrintPass;
267   TimePassesHandler TimePasses;
268   OptNoneInstrumentation OptNone;
269   OptBisectInstrumentation OptBisect;
270   PreservedCFGCheckerInstrumentation PreservedCFGChecker;
271   IRChangedPrinter PrintChangedIR;
272   VerifyInstrumentation Verify;
273 
274   bool VerifyEach;
275 
276 public:
277   StandardInstrumentations(bool DebugLogging, bool VerifyEach = false)
PrintPass(DebugLogging)278       : PrintPass(DebugLogging), OptNone(DebugLogging), Verify(DebugLogging),
279         VerifyEach(VerifyEach) {}
280 
281   void registerCallbacks(PassInstrumentationCallbacks &PIC);
282 
getTimePasses()283   TimePassesHandler &getTimePasses() { return TimePasses; }
284 };
285 
286 extern template class ChangeReporter<std::string>;
287 extern template class TextChangeReporter<std::string>;
288 
289 } // namespace llvm
290 
291 #endif
292