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