Home | History | Annotate | Line # | Download | only in Passes
      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   bool StoreModuleDesc = false;
     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 OptBisectInstrumentation {
     78 public:
     79   OptBisectInstrumentation() {}
     80   void registerCallbacks(PassInstrumentationCallbacks &PIC);
     81 };
     82 
     83 struct PrintPassOptions {
     84   /// Print adaptors and pass managers.
     85   bool Verbose = false;
     86   /// Don't print information for analyses.
     87   bool SkipAnalyses = false;
     88   /// Indent based on hierarchy.
     89   bool Indent = false;
     90 };
     91 
     92 // Debug logging for transformation and analysis passes.
     93 class PrintPassInstrumentation {
     94   raw_ostream &print();
     95 
     96 public:
     97   PrintPassInstrumentation(bool Enabled, PrintPassOptions Opts)
     98       : Enabled(Enabled), Opts(Opts) {}
     99   void registerCallbacks(PassInstrumentationCallbacks &PIC);
    100 
    101 private:
    102   bool Enabled;
    103   PrintPassOptions Opts;
    104   int Indent = 0;
    105 };
    106 
    107 class PreservedCFGCheckerInstrumentation {
    108 public:
    109   // Keeps sticky poisoned flag for the given basic block once it has been
    110   // deleted or RAUWed.
    111   struct BBGuard final : public CallbackVH {
    112     BBGuard(const BasicBlock *BB) : CallbackVH(BB) {}
    113     void deleted() override { CallbackVH::deleted(); }
    114     void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); }
    115     bool isPoisoned() const { return !getValPtr(); }
    116   };
    117 
    118   // CFG is a map BB -> {(Succ, Multiplicity)}, where BB is a non-leaf basic
    119   // block, {(Succ, Multiplicity)} set of all pairs of the block's successors
    120   // and the multiplicity of the edge (BB->Succ). As the mapped sets are
    121   // unordered the order of successors is not tracked by the CFG. In other words
    122   // this allows basic block successors to be swapped by a pass without
    123   // reporting a CFG change. CFG can be guarded by basic block tracking pointers
    124   // in the Graph (BBGuard). That is if any of the block is deleted or RAUWed
    125   // then the CFG is treated poisoned and no block pointer of the Graph is used.
    126   struct CFG {
    127     Optional<DenseMap<intptr_t, BBGuard>> BBGuards;
    128     DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph;
    129 
    130     CFG(const Function *F, bool TrackBBLifetime);
    131 
    132     bool operator==(const CFG &G) const {
    133       return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph;
    134     }
    135 
    136     bool isPoisoned() const {
    137       return BBGuards &&
    138              std::any_of(BBGuards->begin(), BBGuards->end(),
    139                          [](const auto &BB) { return BB.second.isPoisoned(); });
    140     }
    141 
    142     static void printDiff(raw_ostream &out, const CFG &Before,
    143                           const CFG &After);
    144     bool invalidate(Function &F, const PreservedAnalyses &PA,
    145                     FunctionAnalysisManager::Invalidator &);
    146   };
    147 
    148 #ifndef NDEBUG
    149   SmallVector<StringRef, 8> PassStack;
    150 #endif
    151 
    152   static cl::opt<bool> VerifyPreservedCFG;
    153   void registerCallbacks(PassInstrumentationCallbacks &PIC,
    154                          FunctionAnalysisManager &FAM);
    155 };
    156 
    157 // Base class for classes that report changes to the IR.
    158 // It presents an interface for such classes and provides calls
    159 // on various events as the new pass manager transforms the IR.
    160 // It also provides filtering of information based on hidden options
    161 // specifying which functions are interesting.
    162 // Calls are made for the following events/queries:
    163 // 1.  The initial IR processed.
    164 // 2.  To get the representation of the IR (of type \p T).
    165 // 3.  When a pass does not change the IR.
    166 // 4.  When a pass changes the IR (given both before and after representations
    167 //         of type \p T).
    168 // 5.  When an IR is invalidated.
    169 // 6.  When a pass is run on an IR that is not interesting (based on options).
    170 // 7.  When a pass is ignored (pass manager or adapter pass).
    171 // 8.  To compare two IR representations (of type \p T).
    172 template <typename IRUnitT> class ChangeReporter {
    173 protected:
    174   ChangeReporter(bool RunInVerboseMode) : VerboseMode(RunInVerboseMode) {}
    175 
    176 public:
    177   virtual ~ChangeReporter();
    178 
    179   // Determine if this pass/IR is interesting and if so, save the IR
    180   // otherwise it is left on the stack without data.
    181   void saveIRBeforePass(Any IR, StringRef PassID);
    182   // Compare the IR from before the pass after the pass.
    183   void handleIRAfterPass(Any IR, StringRef PassID);
    184   // Handle the situation where a pass is invalidated.
    185   void handleInvalidatedPass(StringRef PassID);
    186 
    187 protected:
    188   // Register required callbacks.
    189   void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC);
    190 
    191   // Return true when this is a defined function for which printing
    192   // of changes is desired.
    193   bool isInterestingFunction(const Function &F);
    194 
    195   // Return true when this is a pass for which printing of changes is desired.
    196   bool isInterestingPass(StringRef PassID);
    197 
    198   // Return true when this is a pass on IR for which printing
    199   // of changes is desired.
    200   bool isInteresting(Any IR, StringRef PassID);
    201 
    202   // Called on the first IR processed.
    203   virtual void handleInitialIR(Any IR) = 0;
    204   // Called before and after a pass to get the representation of the IR.
    205   virtual void generateIRRepresentation(Any IR, StringRef PassID,
    206                                         IRUnitT &Output) = 0;
    207   // Called when the pass is not iteresting.
    208   virtual void omitAfter(StringRef PassID, std::string &Name) = 0;
    209   // Called when an interesting IR has changed.
    210   virtual void handleAfter(StringRef PassID, std::string &Name,
    211                            const IRUnitT &Before, const IRUnitT &After,
    212                            Any) = 0;
    213   // Called when an interesting pass is invalidated.
    214   virtual void handleInvalidated(StringRef PassID) = 0;
    215   // Called when the IR or pass is not interesting.
    216   virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
    217   // Called when an ignored pass is encountered.
    218   virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
    219   // Called to compare the before and after representations of the IR.
    220   virtual bool same(const IRUnitT &Before, const IRUnitT &After) = 0;
    221 
    222   // Stack of IRs before passes.
    223   std::vector<IRUnitT> BeforeStack;
    224   // Is this the first IR seen?
    225   bool InitialIR = true;
    226 
    227   // Run in verbose mode, printing everything?
    228   const bool VerboseMode;
    229 };
    230 
    231 // An abstract template base class that handles printing banners and
    232 // reporting when things have not changed or are filtered out.
    233 template <typename IRUnitT>
    234 class TextChangeReporter : public ChangeReporter<IRUnitT> {
    235 protected:
    236   TextChangeReporter(bool Verbose);
    237 
    238   // Print a module dump of the first IR that is changed.
    239   void handleInitialIR(Any IR) override;
    240   // Report that the IR was omitted because it did not change.
    241   void omitAfter(StringRef PassID, std::string &Name) override;
    242   // Report that the pass was invalidated.
    243   void handleInvalidated(StringRef PassID) override;
    244   // Report that the IR was filtered out.
    245   void handleFiltered(StringRef PassID, std::string &Name) override;
    246   // Report that the pass was ignored.
    247   void handleIgnored(StringRef PassID, std::string &Name) override;
    248   // Make substitutions in \p S suitable for reporting changes
    249   // after the pass and then print it.
    250 
    251   raw_ostream &Out;
    252 };
    253 
    254 // A change printer based on the string representation of the IR as created
    255 // by unwrapAndPrint.  The string representation is stored in a std::string
    256 // to preserve it as the IR changes in each pass.  Note that the banner is
    257 // included in this representation but it is massaged before reporting.
    258 class IRChangedPrinter : public TextChangeReporter<std::string> {
    259 public:
    260   IRChangedPrinter(bool VerboseMode)
    261       : TextChangeReporter<std::string>(VerboseMode) {}
    262   ~IRChangedPrinter() override;
    263   void registerCallbacks(PassInstrumentationCallbacks &PIC);
    264 
    265 protected:
    266   // Called before and after a pass to get the representation of the IR.
    267   void generateIRRepresentation(Any IR, StringRef PassID,
    268                                 std::string &Output) override;
    269   // Called when an interesting IR has changed.
    270   void handleAfter(StringRef PassID, std::string &Name,
    271                    const std::string &Before, const std::string &After,
    272                    Any) override;
    273   // Called to compare the before and after representations of the IR.
    274   bool same(const std::string &Before, const std::string &After) override;
    275 };
    276 
    277 // The following classes hold a representation of the IR for a change
    278 // reporter that uses string comparisons of the basic blocks
    279 // that are created using print (ie, similar to dump()).
    280 // These classes respect the filtering of passes and functions using
    281 // -filter-passes and -filter-print-funcs.
    282 //
    283 // Information that needs to be saved for a basic block in order to compare
    284 // before and after the pass to determine if it was changed by a pass.
    285 class ChangedBlockData {
    286 public:
    287   ChangedBlockData(const BasicBlock &B);
    288 
    289   bool operator==(const ChangedBlockData &That) const {
    290     return Body == That.Body;
    291   }
    292   bool operator!=(const ChangedBlockData &That) const {
    293     return Body != That.Body;
    294   }
    295 
    296   // Return the label of the represented basic block.
    297   StringRef getLabel() const { return Label; }
    298   // Return the string representation of the basic block.
    299   StringRef getBody() const { return Body; }
    300 
    301 protected:
    302   std::string Label;
    303   std::string Body;
    304 };
    305 
    306 template <typename IRData> class OrderedChangedData {
    307 public:
    308   // Return the names in the order they were saved
    309   std::vector<std::string> &getOrder() { return Order; }
    310   const std::vector<std::string> &getOrder() const { return Order; }
    311 
    312   // Return a map of names to saved representations
    313   StringMap<IRData> &getData() { return Data; }
    314   const StringMap<IRData> &getData() const { return Data; }
    315 
    316   bool operator==(const OrderedChangedData<IRData> &That) const {
    317     return Data == That.getData();
    318   }
    319 
    320   // Call the lambda \p HandlePair on each corresponding pair of data from
    321   // \p Before and \p After.  The order is based on the order in \p After
    322   // with ones that are only in \p Before interspersed based on where they
    323   // occur in \p Before.  This is used to present the output in an order
    324   // based on how the data is ordered in LLVM.
    325   static void
    326   report(const OrderedChangedData &Before, const OrderedChangedData &After,
    327          function_ref<void(const IRData *, const IRData *)> HandlePair);
    328 
    329 protected:
    330   std::vector<std::string> Order;
    331   StringMap<IRData> Data;
    332 };
    333 
    334 // The data saved for comparing functions.
    335 using ChangedFuncData = OrderedChangedData<ChangedBlockData>;
    336 
    337 // A map of names to the saved data.
    338 using ChangedIRData = OrderedChangedData<ChangedFuncData>;
    339 
    340 // A class that compares two IRs and does a diff between them.  The
    341 // added lines are prefixed with a '+', the removed lines are prefixed
    342 // with a '-' and unchanged lines are prefixed with a space (to have
    343 // things line up).
    344 class ChangedIRComparer {
    345 public:
    346   ChangedIRComparer(raw_ostream &OS, const ChangedIRData &Before,
    347                     const ChangedIRData &After, bool ColourMode)
    348       : Before(Before), After(After), Out(OS), UseColour(ColourMode) {}
    349 
    350   // Compare the 2 IRs.
    351   void compare(Any IR, StringRef Prefix, StringRef PassID, StringRef Name);
    352 
    353   // Analyze \p IR and build the IR representation in \p Data.
    354   static void analyzeIR(Any IR, ChangedIRData &Data);
    355 
    356 protected:
    357   // Return the module when that is the appropriate level of
    358   // comparison for \p IR.
    359   static const Module *getModuleForComparison(Any IR);
    360 
    361   // Generate the data for \p F into \p Data.
    362   static bool generateFunctionData(ChangedIRData &Data, const Function &F);
    363 
    364   // Called to handle the compare of a function. When \p InModule is set,
    365   // this function is being handled as part of comparing a module.
    366   void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
    367                              bool InModule, const ChangedFuncData &Before,
    368                              const ChangedFuncData &After);
    369 
    370   const ChangedIRData &Before;
    371   const ChangedIRData &After;
    372   raw_ostream &Out;
    373   bool UseColour;
    374 };
    375 
    376 // A change printer that prints out in-line differences in the basic
    377 // blocks.  It uses an InlineComparer to do the comparison so it shows
    378 // the differences prefixed with '-' and '+' for code that is removed
    379 // and added, respectively.  Changes to the IR that do not affect basic
    380 // blocks are not reported as having changed the IR.  The option
    381 // -print-module-scope does not affect this change reporter.
    382 class InLineChangePrinter : public TextChangeReporter<ChangedIRData> {
    383 public:
    384   InLineChangePrinter(bool VerboseMode, bool ColourMode)
    385       : TextChangeReporter<ChangedIRData>(VerboseMode), UseColour(ColourMode) {}
    386   ~InLineChangePrinter() override;
    387   void registerCallbacks(PassInstrumentationCallbacks &PIC);
    388 
    389 protected:
    390   // Create a representation of the IR.
    391   virtual void generateIRRepresentation(Any IR, StringRef PassID,
    392                                         ChangedIRData &Output) override;
    393 
    394   // Called when an interesting IR has changed.
    395   virtual void handleAfter(StringRef PassID, std::string &Name,
    396                            const ChangedIRData &Before,
    397                            const ChangedIRData &After, Any) override;
    398   // Called to compare the before and after representations of the IR.
    399   virtual bool same(const ChangedIRData &Before,
    400                     const ChangedIRData &After) override;
    401 
    402   bool UseColour;
    403 };
    404 
    405 class VerifyInstrumentation {
    406   bool DebugLogging;
    407 
    408 public:
    409   VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
    410   void registerCallbacks(PassInstrumentationCallbacks &PIC);
    411 };
    412 
    413 /// This class provides an interface to register all the standard pass
    414 /// instrumentations and manages their state (if any).
    415 class StandardInstrumentations {
    416   PrintIRInstrumentation PrintIR;
    417   PrintPassInstrumentation PrintPass;
    418   TimePassesHandler TimePasses;
    419   OptNoneInstrumentation OptNone;
    420   OptBisectInstrumentation OptBisect;
    421   PreservedCFGCheckerInstrumentation PreservedCFGChecker;
    422   IRChangedPrinter PrintChangedIR;
    423   PseudoProbeVerifier PseudoProbeVerification;
    424   InLineChangePrinter PrintChangedDiff;
    425   VerifyInstrumentation Verify;
    426 
    427   bool VerifyEach;
    428 
    429 public:
    430   StandardInstrumentations(bool DebugLogging, bool VerifyEach = false,
    431                            PrintPassOptions PrintPassOpts = PrintPassOptions());
    432 
    433   // Register all the standard instrumentation callbacks. If \p FAM is nullptr
    434   // then PreservedCFGChecker is not enabled.
    435   void registerCallbacks(PassInstrumentationCallbacks &PIC,
    436                          FunctionAnalysisManager *FAM = nullptr);
    437 
    438   TimePassesHandler &getTimePasses() { return TimePasses; }
    439 };
    440 
    441 extern template class ChangeReporter<std::string>;
    442 extern template class TextChangeReporter<std::string>;
    443 
    444 extern template class ChangeReporter<ChangedIRData>;
    445 extern template class TextChangeReporter<ChangedIRData>;
    446 
    447 } // namespace llvm
    448 
    449 #endif
    450