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