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