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