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