123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- StandardInstrumentations.h ------------------------------*- C++ -*--===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- /// \file
- ///
- /// This header defines a class that provides bookkeeping for all standard
- /// (i.e in-tree) pass instrumentations.
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_PASSES_STANDARDINSTRUMENTATIONS_H
- #define LLVM_PASSES_STANDARDINSTRUMENTATIONS_H
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/IR/BasicBlock.h"
- #include "llvm/IR/OptBisect.h"
- #include "llvm/IR/PassTimingInfo.h"
- #include "llvm/IR/ValueHandle.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/TimeProfiler.h"
- #include "llvm/Transforms/IPO/SampleProfileProbe.h"
- #include <string>
- #include <utility>
- namespace llvm {
- class Module;
- class Function;
- class PassInstrumentationCallbacks;
- /// Instrumentation to print IR before/after passes.
- ///
- /// Needs state to be able to print module after pass that invalidates IR unit
- /// (typically Loop or SCC).
- class PrintIRInstrumentation {
- public:
- ~PrintIRInstrumentation();
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- private:
- void printBeforePass(StringRef PassID, Any IR);
- void printAfterPass(StringRef PassID, Any IR);
- void printAfterPassInvalidated(StringRef PassID);
- bool shouldPrintBeforePass(StringRef PassID);
- bool shouldPrintAfterPass(StringRef PassID);
- using PrintModuleDesc = std::tuple<const Module *, std::string, StringRef>;
- void pushModuleDesc(StringRef PassID, Any IR);
- PrintModuleDesc popModuleDesc(StringRef PassID);
- PassInstrumentationCallbacks *PIC;
- /// Stack of Module description, enough to print the module after a given
- /// pass.
- SmallVector<PrintModuleDesc, 2> ModuleDescStack;
- };
- class OptNoneInstrumentation {
- public:
- OptNoneInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- private:
- bool DebugLogging;
- bool shouldRun(StringRef PassID, Any IR);
- };
- class OptPassGateInstrumentation {
- LLVMContext &Context;
- bool HasWrittenIR = false;
- public:
- OptPassGateInstrumentation(LLVMContext &Context) : Context(Context) {}
- bool shouldRun(StringRef PassName, Any IR);
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- };
- struct PrintPassOptions {
- /// Print adaptors and pass managers.
- bool Verbose = false;
- /// Don't print information for analyses.
- bool SkipAnalyses = false;
- /// Indent based on hierarchy.
- bool Indent = false;
- };
- // Debug logging for transformation and analysis passes.
- class PrintPassInstrumentation {
- raw_ostream &print();
- public:
- PrintPassInstrumentation(bool Enabled, PrintPassOptions Opts)
- : Enabled(Enabled), Opts(Opts) {}
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- private:
- bool Enabled;
- PrintPassOptions Opts;
- int Indent = 0;
- };
- class PreservedCFGCheckerInstrumentation {
- public:
- // Keeps sticky poisoned flag for the given basic block once it has been
- // deleted or RAUWed.
- struct BBGuard final : public CallbackVH {
- BBGuard(const BasicBlock *BB) : CallbackVH(BB) {}
- void deleted() override { CallbackVH::deleted(); }
- void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); }
- bool isPoisoned() const { return !getValPtr(); }
- };
- // CFG is a map BB -> {(Succ, Multiplicity)}, where BB is a non-leaf basic
- // block, {(Succ, Multiplicity)} set of all pairs of the block's successors
- // and the multiplicity of the edge (BB->Succ). As the mapped sets are
- // unordered the order of successors is not tracked by the CFG. In other words
- // this allows basic block successors to be swapped by a pass without
- // reporting a CFG change. CFG can be guarded by basic block tracking pointers
- // in the Graph (BBGuard). That is if any of the block is deleted or RAUWed
- // then the CFG is treated poisoned and no block pointer of the Graph is used.
- struct CFG {
- std::optional<DenseMap<intptr_t, BBGuard>> BBGuards;
- DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph;
- CFG(const Function *F, bool TrackBBLifetime);
- bool operator==(const CFG &G) const {
- return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph;
- }
- bool isPoisoned() const {
- return BBGuards && llvm::any_of(*BBGuards, [](const auto &BB) {
- return BB.second.isPoisoned();
- });
- }
- static void printDiff(raw_ostream &out, const CFG &Before,
- const CFG &After);
- bool invalidate(Function &F, const PreservedAnalyses &PA,
- FunctionAnalysisManager::Invalidator &);
- };
- #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
- SmallVector<StringRef, 8> PassStack;
- #endif
- static cl::opt<bool> VerifyPreservedCFG;
- void registerCallbacks(PassInstrumentationCallbacks &PIC,
- FunctionAnalysisManager &FAM);
- };
- // Base class for classes that report changes to the IR.
- // It presents an interface for such classes and provides calls
- // on various events as the new pass manager transforms the IR.
- // It also provides filtering of information based on hidden options
- // specifying which functions are interesting.
- // Calls are made for the following events/queries:
- // 1. The initial IR processed.
- // 2. To get the representation of the IR (of type \p T).
- // 3. When a pass does not change the IR.
- // 4. When a pass changes the IR (given both before and after representations
- // of type \p T).
- // 5. When an IR is invalidated.
- // 6. When a pass is run on an IR that is not interesting (based on options).
- // 7. When a pass is ignored (pass manager or adapter pass).
- // 8. To compare two IR representations (of type \p T).
- template <typename IRUnitT> class ChangeReporter {
- protected:
- ChangeReporter(bool RunInVerboseMode) : VerboseMode(RunInVerboseMode) {}
- public:
- virtual ~ChangeReporter();
- // Determine if this pass/IR is interesting and if so, save the IR
- // otherwise it is left on the stack without data.
- void saveIRBeforePass(Any IR, StringRef PassID, StringRef PassName);
- // Compare the IR from before the pass after the pass.
- void handleIRAfterPass(Any IR, StringRef PassID, StringRef PassName);
- // Handle the situation where a pass is invalidated.
- void handleInvalidatedPass(StringRef PassID);
- protected:
- // Register required callbacks.
- void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC);
- // Called on the first IR processed.
- virtual void handleInitialIR(Any IR) = 0;
- // Called before and after a pass to get the representation of the IR.
- virtual void generateIRRepresentation(Any IR, StringRef PassID,
- IRUnitT &Output) = 0;
- // Called when the pass is not iteresting.
- virtual void omitAfter(StringRef PassID, std::string &Name) = 0;
- // Called when an interesting IR has changed.
- virtual void handleAfter(StringRef PassID, std::string &Name,
- const IRUnitT &Before, const IRUnitT &After,
- Any) = 0;
- // Called when an interesting pass is invalidated.
- virtual void handleInvalidated(StringRef PassID) = 0;
- // Called when the IR or pass is not interesting.
- virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
- // Called when an ignored pass is encountered.
- virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
- // Stack of IRs before passes.
- std::vector<IRUnitT> BeforeStack;
- // Is this the first IR seen?
- bool InitialIR = true;
- // Run in verbose mode, printing everything?
- const bool VerboseMode;
- };
- // An abstract template base class that handles printing banners and
- // reporting when things have not changed or are filtered out.
- template <typename IRUnitT>
- class TextChangeReporter : public ChangeReporter<IRUnitT> {
- protected:
- TextChangeReporter(bool Verbose);
- // Print a module dump of the first IR that is changed.
- void handleInitialIR(Any IR) override;
- // Report that the IR was omitted because it did not change.
- void omitAfter(StringRef PassID, std::string &Name) override;
- // Report that the pass was invalidated.
- void handleInvalidated(StringRef PassID) override;
- // Report that the IR was filtered out.
- void handleFiltered(StringRef PassID, std::string &Name) override;
- // Report that the pass was ignored.
- void handleIgnored(StringRef PassID, std::string &Name) override;
- // Make substitutions in \p S suitable for reporting changes
- // after the pass and then print it.
- raw_ostream &Out;
- };
- // A change printer based on the string representation of the IR as created
- // by unwrapAndPrint. The string representation is stored in a std::string
- // to preserve it as the IR changes in each pass. Note that the banner is
- // included in this representation but it is massaged before reporting.
- class IRChangedPrinter : public TextChangeReporter<std::string> {
- public:
- IRChangedPrinter(bool VerboseMode)
- : TextChangeReporter<std::string>(VerboseMode) {}
- ~IRChangedPrinter() override;
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- protected:
- // Called before and after a pass to get the representation of the IR.
- void generateIRRepresentation(Any IR, StringRef PassID,
- std::string &Output) override;
- // Called when an interesting IR has changed.
- void handleAfter(StringRef PassID, std::string &Name,
- const std::string &Before, const std::string &After,
- Any) override;
- };
- class IRChangedTester : public IRChangedPrinter {
- public:
- IRChangedTester() : IRChangedPrinter(true) {}
- ~IRChangedTester() override;
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- protected:
- void handleIR(const std::string &IR, StringRef PassID);
- // Check initial IR
- void handleInitialIR(Any IR) override;
- // Do nothing.
- void omitAfter(StringRef PassID, std::string &Name) override;
- // Do nothing.
- void handleInvalidated(StringRef PassID) override;
- // Do nothing.
- void handleFiltered(StringRef PassID, std::string &Name) override;
- // Do nothing.
- void handleIgnored(StringRef PassID, std::string &Name) override;
- // Call test as interesting IR has changed.
- void handleAfter(StringRef PassID, std::string &Name,
- const std::string &Before, const std::string &After,
- Any) override;
- };
- // Information that needs to be saved for a basic block in order to compare
- // before and after the pass to determine if it was changed by a pass.
- template <typename T> class BlockDataT {
- public:
- BlockDataT(const BasicBlock &B) : Label(B.getName().str()), Data(B) {
- raw_string_ostream SS(Body);
- B.print(SS, nullptr, true, true);
- }
- bool operator==(const BlockDataT &That) const { return Body == That.Body; }
- bool operator!=(const BlockDataT &That) const { return Body != That.Body; }
- // Return the label of the represented basic block.
- StringRef getLabel() const { return Label; }
- // Return the string representation of the basic block.
- StringRef getBody() const { return Body; }
- // Return the associated data
- const T &getData() const { return Data; }
- protected:
- std::string Label;
- std::string Body;
- // Extra data associated with a basic block
- T Data;
- };
- template <typename T> class OrderedChangedData {
- public:
- // Return the names in the order they were saved
- std::vector<std::string> &getOrder() { return Order; }
- const std::vector<std::string> &getOrder() const { return Order; }
- // Return a map of names to saved representations
- StringMap<T> &getData() { return Data; }
- const StringMap<T> &getData() const { return Data; }
- bool operator==(const OrderedChangedData<T> &That) const {
- return Data == That.getData();
- }
- // Call the lambda \p HandlePair on each corresponding pair of data from
- // \p Before and \p After. The order is based on the order in \p After
- // with ones that are only in \p Before interspersed based on where they
- // occur in \p Before. This is used to present the output in an order
- // based on how the data is ordered in LLVM.
- static void report(const OrderedChangedData &Before,
- const OrderedChangedData &After,
- function_ref<void(const T *, const T *)> HandlePair);
- protected:
- std::vector<std::string> Order;
- StringMap<T> Data;
- };
- // Do not need extra information for patch-style change reporter.
- class EmptyData {
- public:
- EmptyData(const BasicBlock &) {}
- };
- // The data saved for comparing functions.
- template <typename T>
- class FuncDataT : public OrderedChangedData<BlockDataT<T>> {
- public:
- FuncDataT(std::string S) : EntryBlockName(S) {}
- // Return the name of the entry block
- std::string getEntryBlockName() const { return EntryBlockName; }
- protected:
- std::string EntryBlockName;
- };
- // The data saved for comparing IRs.
- template <typename T>
- class IRDataT : public OrderedChangedData<FuncDataT<T>> {};
- // Abstract template base class for a class that compares two IRs. The
- // class is created with the 2 IRs to compare and then compare is called.
- // The static function analyzeIR is used to build up the IR representation.
- template <typename T> class IRComparer {
- public:
- IRComparer(const IRDataT<T> &Before, const IRDataT<T> &After)
- : Before(Before), After(After) {}
- // Compare the 2 IRs. \p handleFunctionCompare is called to handle the
- // compare of a function. When \p InModule is set,
- // this function is being handled as part of comparing a module.
- void compare(
- bool CompareModule,
- std::function<void(bool InModule, unsigned Minor,
- const FuncDataT<T> &Before, const FuncDataT<T> &After)>
- CompareFunc);
- // Analyze \p IR and build the IR representation in \p Data.
- static void analyzeIR(Any IR, IRDataT<T> &Data);
- protected:
- // Generate the data for \p F into \p Data.
- static bool generateFunctionData(IRDataT<T> &Data, const Function &F);
- const IRDataT<T> &Before;
- const IRDataT<T> &After;
- };
- // A change printer that prints out in-line differences in the basic
- // blocks. It uses an InlineComparer to do the comparison so it shows
- // the differences prefixed with '-' and '+' for code that is removed
- // and added, respectively. Changes to the IR that do not affect basic
- // blocks are not reported as having changed the IR. The option
- // -print-module-scope does not affect this change reporter.
- class InLineChangePrinter : public TextChangeReporter<IRDataT<EmptyData>> {
- public:
- InLineChangePrinter(bool VerboseMode, bool ColourMode)
- : TextChangeReporter<IRDataT<EmptyData>>(VerboseMode),
- UseColour(ColourMode) {}
- ~InLineChangePrinter() override;
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- protected:
- // Create a representation of the IR.
- void generateIRRepresentation(Any IR, StringRef PassID,
- IRDataT<EmptyData> &Output) override;
- // Called when an interesting IR has changed.
- void handleAfter(StringRef PassID, std::string &Name,
- const IRDataT<EmptyData> &Before,
- const IRDataT<EmptyData> &After, Any) override;
- void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
- StringRef Divider, bool InModule, unsigned Minor,
- const FuncDataT<EmptyData> &Before,
- const FuncDataT<EmptyData> &After);
- bool UseColour;
- };
- class VerifyInstrumentation {
- bool DebugLogging;
- public:
- VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- };
- /// This class implements --time-trace functionality for new pass manager.
- /// It provides the pass-instrumentation callbacks that measure the pass
- /// execution time. They collect time tracing info by TimeProfiler.
- class TimeProfilingPassesHandler {
- public:
- TimeProfilingPassesHandler();
- // We intend this to be unique per-compilation, thus no copies.
- TimeProfilingPassesHandler(const TimeProfilingPassesHandler &) = delete;
- void operator=(const TimeProfilingPassesHandler &) = delete;
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- private:
- // Implementation of pass instrumentation callbacks.
- void runBeforePass(StringRef PassID, Any IR);
- void runAfterPass();
- };
- // Class that holds transitions between basic blocks. The transitions
- // are contained in a map of values to names of basic blocks.
- class DCData {
- public:
- // Fill the map with the transitions from basic block \p B.
- DCData(const BasicBlock &B);
- // Return an iterator to the names of the successor blocks.
- StringMap<std::string>::const_iterator begin() const {
- return Successors.begin();
- }
- StringMap<std::string>::const_iterator end() const {
- return Successors.end();
- }
- // Return the label of the basic block reached on a transition on \p S.
- StringRef getSuccessorLabel(StringRef S) const {
- assert(Successors.count(S) == 1 && "Expected to find successor.");
- return Successors.find(S)->getValue();
- }
- protected:
- // Add a transition to \p Succ on \p Label
- void addSuccessorLabel(StringRef Succ, StringRef Label) {
- std::pair<std::string, std::string> SS{Succ.str(), Label.str()};
- Successors.insert(SS);
- }
- StringMap<std::string> Successors;
- };
- // A change reporter that builds a website with links to pdf files showing
- // dot control flow graphs with changed instructions shown in colour.
- class DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
- public:
- DotCfgChangeReporter(bool Verbose);
- ~DotCfgChangeReporter() override;
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- protected:
- // Initialize the HTML file and output the header.
- bool initializeHTML();
- // Called on the first IR processed.
- void handleInitialIR(Any IR) override;
- // Called before and after a pass to get the representation of the IR.
- void generateIRRepresentation(Any IR, StringRef PassID,
- IRDataT<DCData> &Output) override;
- // Called when the pass is not iteresting.
- void omitAfter(StringRef PassID, std::string &Name) override;
- // Called when an interesting IR has changed.
- void handleAfter(StringRef PassID, std::string &Name,
- const IRDataT<DCData> &Before, const IRDataT<DCData> &After,
- Any) override;
- // Called when an interesting pass is invalidated.
- void handleInvalidated(StringRef PassID) override;
- // Called when the IR or pass is not interesting.
- void handleFiltered(StringRef PassID, std::string &Name) override;
- // Called when an ignored pass is encountered.
- void handleIgnored(StringRef PassID, std::string &Name) override;
- // Generate the pdf file into \p Dir / \p PDFFileName using \p DotFile as
- // input and return the html <a> tag with \Text as the content.
- static std::string genHTML(StringRef Text, StringRef DotFile,
- StringRef PDFFileName);
- void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
- StringRef Divider, bool InModule, unsigned Minor,
- const FuncDataT<DCData> &Before,
- const FuncDataT<DCData> &After);
- unsigned N = 0;
- std::unique_ptr<raw_fd_ostream> HTML;
- };
- // Print IR on crash.
- class PrintCrashIRInstrumentation {
- public:
- PrintCrashIRInstrumentation()
- : SavedIR("*** Dump of IR Before Last Pass Unknown ***") {}
- ~PrintCrashIRInstrumentation();
- void registerCallbacks(PassInstrumentationCallbacks &PIC);
- void reportCrashIR();
- protected:
- std::string SavedIR;
- private:
- // The crash reporter that will report on a crash.
- static PrintCrashIRInstrumentation *CrashReporter;
- // Crash handler registered when print-on-crash is specified.
- static void SignalHandler(void *);
- };
- /// This class provides an interface to register all the standard pass
- /// instrumentations and manages their state (if any).
- class StandardInstrumentations {
- PrintIRInstrumentation PrintIR;
- PrintPassInstrumentation PrintPass;
- TimePassesHandler TimePasses;
- TimeProfilingPassesHandler TimeProfilingPasses;
- OptNoneInstrumentation OptNone;
- OptPassGateInstrumentation OptPassGate;
- PreservedCFGCheckerInstrumentation PreservedCFGChecker;
- IRChangedPrinter PrintChangedIR;
- PseudoProbeVerifier PseudoProbeVerification;
- InLineChangePrinter PrintChangedDiff;
- DotCfgChangeReporter WebsiteChangeReporter;
- PrintCrashIRInstrumentation PrintCrashIR;
- IRChangedTester ChangeTester;
- VerifyInstrumentation Verify;
- bool VerifyEach;
- public:
- StandardInstrumentations(LLVMContext &Context, bool DebugLogging,
- bool VerifyEach = false,
- PrintPassOptions PrintPassOpts = PrintPassOptions());
- // Register all the standard instrumentation callbacks. If \p FAM is nullptr
- // then PreservedCFGChecker is not enabled.
- void registerCallbacks(PassInstrumentationCallbacks &PIC,
- FunctionAnalysisManager *FAM = nullptr);
- TimePassesHandler &getTimePasses() { return TimePasses; }
- };
- extern template class ChangeReporter<std::string>;
- extern template class TextChangeReporter<std::string>;
- extern template class BlockDataT<EmptyData>;
- extern template class FuncDataT<EmptyData>;
- extern template class IRDataT<EmptyData>;
- extern template class ChangeReporter<IRDataT<EmptyData>>;
- extern template class TextChangeReporter<IRDataT<EmptyData>>;
- extern template class IRComparer<EmptyData>;
- } // namespace llvm
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|