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