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 |