Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 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: | ||
| 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: | ||
| 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: | ||
| 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 { | ||
| 115 | BBGuard(const BasicBlock *BB) : CallbackVH(BB) {} | ||
| 116 | void deleted() override { CallbackVH::deleted(); } | ||
| 117 | void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); } | ||
| 118 | 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 | |||
| 139 | 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: | ||
| 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: | ||
| 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: | ||
| 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: | ||
| 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. | ||
| 304 | StringRef getLabel() const { return Label; } | ||
| 305 |   // Return the string representation of the basic block. | ||
| 306 | StringRef getBody() const { return Body; } | ||
| 307 | |||
| 308 |   // Return the associated data | ||
| 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 | ||
| 322 | std::vector<std::string> &getOrder() { return Order; } | ||
| 323 | const std::vector<std::string> &getOrder() const { return Order; } | ||
| 324 | |||
| 325 |   // Return a map of names to saved representations | ||
| 326 | StringMap<T> &getData() { return Data; } | ||
| 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: | ||
| 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: | ||
| 357 | FuncDataT(std::string S) : EntryBlockName(S) {} | ||
| 358 | |||
| 359 |   // Return the name of the entry block | ||
| 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: | ||
| 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: | ||
| 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: | ||
| 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. | ||
| 464 | StringMap<std::string>::const_iterator begin() const { | ||
| 465 | return Successors.begin(); | ||
| 466 |   } | ||
| 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. | ||
| 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 | ||
| 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: | ||
| 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 | |||
| 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 |