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
32namespace llvm {
33
34class Module;
35class Function;
36class 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).
42class PrintIRInstrumentation {
43public:
44 ~PrintIRInstrumentation();
45
46 void registerCallbacks(PassInstrumentationCallbacks &PIC);
47
48private:
49 struct PassRunDescriptor {
50 const Module *M;
51 const std::string DumpIRFilename;
52 const std::string IRName;
53 const StringRef PassID;
54
55 PassRunDescriptor(const Module *M, std::string DumpIRFilename,
56 std::string IRName, const StringRef PassID)
57 : M{M}, DumpIRFilename{DumpIRFilename}, IRName{IRName}, PassID(PassID) {
58 }
59 };
60
61 void printBeforePass(StringRef PassID, Any IR);
62 void printAfterPass(StringRef PassID, Any IR);
63 void printAfterPassInvalidated(StringRef PassID);
64
65 bool shouldPrintBeforePass(StringRef PassID);
66 bool shouldPrintAfterPass(StringRef PassID);
67 bool shouldPrintPassNumbers();
68 bool shouldPrintBeforePassNumber();
69
70 void pushPassRunDescriptor(StringRef PassID, Any IR,
71 std::string &DumpIRFilename);
72 PassRunDescriptor popPassRunDescriptor(StringRef PassID);
73 std::string fetchDumpFilename(StringRef PassId, Any IR);
74
75 PassInstrumentationCallbacks *PIC;
76 /// Stack of Pass Run descriptions, enough to print the IR unit after a given
77 /// pass.
78 SmallVector<PassRunDescriptor, 2> PassRunDescriptorStack;
79
80 /// Used for print-at-pass-number
81 unsigned CurrentPassNumber = 0;
82};
83
84class OptNoneInstrumentation {
85public:
86 OptNoneInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
87 void registerCallbacks(PassInstrumentationCallbacks &PIC);
88
89private:
90 bool DebugLogging;
91 bool shouldRun(StringRef PassID, Any IR);
92};
93
94class OptPassGateInstrumentation {
95 LLVMContext &Context;
96 bool HasWrittenIR = false;
97public:
98 OptPassGateInstrumentation(LLVMContext &Context) : Context(Context) {}
99 bool shouldRun(StringRef PassName, Any IR);
100 void registerCallbacks(PassInstrumentationCallbacks &PIC);
101};
102
103struct PrintPassOptions {
104 /// Print adaptors and pass managers.
105 bool Verbose = false;
106 /// Don't print information for analyses.
107 bool SkipAnalyses = false;
108 /// Indent based on hierarchy.
109 bool Indent = false;
110};
111
112// Debug logging for transformation and analysis passes.
113class PrintPassInstrumentation {
114 raw_ostream &print();
115
116public:
117 PrintPassInstrumentation(bool Enabled, PrintPassOptions Opts)
118 : Enabled(Enabled), Opts(Opts) {}
119 void registerCallbacks(PassInstrumentationCallbacks &PIC);
120
121private:
122 bool Enabled;
123 PrintPassOptions Opts;
124 int Indent = 0;
125};
126
127class PreservedCFGCheckerInstrumentation {
128public:
129 // Keeps sticky poisoned flag for the given basic block once it has been
130 // deleted or RAUWed.
131 struct BBGuard final : public CallbackVH {
132 BBGuard(const BasicBlock *BB) : CallbackVH(BB) {}
133 void deleted() override { CallbackVH::deleted(); }
134 void allUsesReplacedWith(Value *) override { CallbackVH::deleted(); }
135 bool isPoisoned() const { return !getValPtr(); }
136 };
137
138 // CFG is a map BB -> {(Succ, Multiplicity)}, where BB is a non-leaf basic
139 // block, {(Succ, Multiplicity)} set of all pairs of the block's successors
140 // and the multiplicity of the edge (BB->Succ). As the mapped sets are
141 // unordered the order of successors is not tracked by the CFG. In other words
142 // this allows basic block successors to be swapped by a pass without
143 // reporting a CFG change. CFG can be guarded by basic block tracking pointers
144 // in the Graph (BBGuard). That is if any of the block is deleted or RAUWed
145 // then the CFG is treated poisoned and no block pointer of the Graph is used.
146 struct CFG {
147 std::optional<DenseMap<intptr_t, BBGuard>> BBGuards;
148 DenseMap<const BasicBlock *, DenseMap<const BasicBlock *, unsigned>> Graph;
149
150 CFG(const Function *F, bool TrackBBLifetime);
151
152 bool operator==(const CFG &G) const {
153 return !isPoisoned() && !G.isPoisoned() && Graph == G.Graph;
154 }
155
156 bool isPoisoned() const {
157 return BBGuards && llvm::any_of(Range: *BBGuards, P: [](const auto &BB) {
158 return BB.second.isPoisoned();
159 });
160 }
161
162 static void printDiff(raw_ostream &out, const CFG &Before,
163 const CFG &After);
164 bool invalidate(Function &F, const PreservedAnalyses &PA,
165 FunctionAnalysisManager::Invalidator &);
166 };
167
168#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
169 SmallVector<StringRef, 8> PassStack;
170#endif
171
172 void registerCallbacks(PassInstrumentationCallbacks &PIC,
173 ModuleAnalysisManager &MAM);
174};
175
176// Base class for classes that report changes to the IR.
177// It presents an interface for such classes and provides calls
178// on various events as the new pass manager transforms the IR.
179// It also provides filtering of information based on hidden options
180// specifying which functions are interesting.
181// Calls are made for the following events/queries:
182// 1. The initial IR processed.
183// 2. To get the representation of the IR (of type \p T).
184// 3. When a pass does not change the IR.
185// 4. When a pass changes the IR (given both before and after representations
186// of type \p T).
187// 5. When an IR is invalidated.
188// 6. When a pass is run on an IR that is not interesting (based on options).
189// 7. When a pass is ignored (pass manager or adapter pass).
190// 8. To compare two IR representations (of type \p T).
191template <typename IRUnitT> class ChangeReporter {
192protected:
193 ChangeReporter(bool RunInVerboseMode) : VerboseMode(RunInVerboseMode) {}
194
195public:
196 virtual ~ChangeReporter();
197
198 // Determine if this pass/IR is interesting and if so, save the IR
199 // otherwise it is left on the stack without data.
200 void saveIRBeforePass(Any IR, StringRef PassID, StringRef PassName);
201 // Compare the IR from before the pass after the pass.
202 void handleIRAfterPass(Any IR, StringRef PassID, StringRef PassName);
203 // Handle the situation where a pass is invalidated.
204 void handleInvalidatedPass(StringRef PassID);
205
206protected:
207 // Register required callbacks.
208 void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC);
209
210 // Called on the first IR processed.
211 virtual void handleInitialIR(Any IR) = 0;
212 // Called before and after a pass to get the representation of the IR.
213 virtual void generateIRRepresentation(Any IR, StringRef PassID,
214 IRUnitT &Output) = 0;
215 // Called when the pass is not iteresting.
216 virtual void omitAfter(StringRef PassID, std::string &Name) = 0;
217 // Called when an interesting IR has changed.
218 virtual void handleAfter(StringRef PassID, std::string &Name,
219 const IRUnitT &Before, const IRUnitT &After,
220 Any) = 0;
221 // Called when an interesting pass is invalidated.
222 virtual void handleInvalidated(StringRef PassID) = 0;
223 // Called when the IR or pass is not interesting.
224 virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
225 // Called when an ignored pass is encountered.
226 virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
227
228 // Stack of IRs before passes.
229 std::vector<IRUnitT> BeforeStack;
230 // Is this the first IR seen?
231 bool InitialIR = true;
232
233 // Run in verbose mode, printing everything?
234 const bool VerboseMode;
235};
236
237// An abstract template base class that handles printing banners and
238// reporting when things have not changed or are filtered out.
239template <typename IRUnitT>
240class TextChangeReporter : public ChangeReporter<IRUnitT> {
241protected:
242 TextChangeReporter(bool Verbose);
243
244 // Print a module dump of the first IR that is changed.
245 void handleInitialIR(Any IR) override;
246 // Report that the IR was omitted because it did not change.
247 void omitAfter(StringRef PassID, std::string &Name) override;
248 // Report that the pass was invalidated.
249 void handleInvalidated(StringRef PassID) override;
250 // Report that the IR was filtered out.
251 void handleFiltered(StringRef PassID, std::string &Name) override;
252 // Report that the pass was ignored.
253 void handleIgnored(StringRef PassID, std::string &Name) override;
254 // Make substitutions in \p S suitable for reporting changes
255 // after the pass and then print it.
256
257 raw_ostream &Out;
258};
259
260// A change printer based on the string representation of the IR as created
261// by unwrapAndPrint. The string representation is stored in a std::string
262// to preserve it as the IR changes in each pass. Note that the banner is
263// included in this representation but it is massaged before reporting.
264class IRChangedPrinter : public TextChangeReporter<std::string> {
265public:
266 IRChangedPrinter(bool VerboseMode)
267 : TextChangeReporter<std::string>(VerboseMode) {}
268 ~IRChangedPrinter() override;
269 void registerCallbacks(PassInstrumentationCallbacks &PIC);
270
271protected:
272 // Called before and after a pass to get the representation of the IR.
273 void generateIRRepresentation(Any IR, StringRef PassID,
274 std::string &Output) override;
275 // Called when an interesting IR has changed.
276 void handleAfter(StringRef PassID, std::string &Name,
277 const std::string &Before, const std::string &After,
278 Any) override;
279};
280
281class IRChangedTester : public IRChangedPrinter {
282public:
283 IRChangedTester() : IRChangedPrinter(true) {}
284 ~IRChangedTester() override;
285 void registerCallbacks(PassInstrumentationCallbacks &PIC);
286
287protected:
288 void handleIR(const std::string &IR, StringRef PassID);
289
290 // Check initial IR
291 void handleInitialIR(Any IR) override;
292 // Do nothing.
293 void omitAfter(StringRef PassID, std::string &Name) override;
294 // Do nothing.
295 void handleInvalidated(StringRef PassID) override;
296 // Do nothing.
297 void handleFiltered(StringRef PassID, std::string &Name) override;
298 // Do nothing.
299 void handleIgnored(StringRef PassID, std::string &Name) override;
300
301 // Call test as interesting IR has changed.
302 void handleAfter(StringRef PassID, std::string &Name,
303 const std::string &Before, const std::string &After,
304 Any) override;
305};
306
307// Information that needs to be saved for a basic block in order to compare
308// before and after the pass to determine if it was changed by a pass.
309template <typename T> class BlockDataT {
310public:
311 BlockDataT(const BasicBlock &B) : Label(B.getName().str()), Data(B) {
312 raw_string_ostream SS(Body);
313 B.print(OS&: SS, AAW: nullptr, ShouldPreserveUseListOrder: true, IsForDebug: true);
314 }
315
316 bool operator==(const BlockDataT &That) const { return Body == That.Body; }
317 bool operator!=(const BlockDataT &That) const { return Body != That.Body; }
318
319 // Return the label of the represented basic block.
320 StringRef getLabel() const { return Label; }
321 // Return the string representation of the basic block.
322 StringRef getBody() const { return Body; }
323
324 // Return the associated data
325 const T &getData() const { return Data; }
326
327protected:
328 std::string Label;
329 std::string Body;
330
331 // Extra data associated with a basic block
332 T Data;
333};
334
335template <typename T> class OrderedChangedData {
336public:
337 // Return the names in the order they were saved
338 std::vector<std::string> &getOrder() { return Order; }
339 const std::vector<std::string> &getOrder() const { return Order; }
340
341 // Return a map of names to saved representations
342 StringMap<T> &getData() { return Data; }
343 const StringMap<T> &getData() const { return Data; }
344
345 bool operator==(const OrderedChangedData<T> &That) const {
346 return Data == That.getData();
347 }
348
349 // Call the lambda \p HandlePair on each corresponding pair of data from
350 // \p Before and \p After. The order is based on the order in \p After
351 // with ones that are only in \p Before interspersed based on where they
352 // occur in \p Before. This is used to present the output in an order
353 // based on how the data is ordered in LLVM.
354 static void report(const OrderedChangedData &Before,
355 const OrderedChangedData &After,
356 function_ref<void(const T *, const T *)> HandlePair);
357
358protected:
359 std::vector<std::string> Order;
360 StringMap<T> Data;
361};
362
363// Do not need extra information for patch-style change reporter.
364class EmptyData {
365public:
366 EmptyData(const BasicBlock &) {}
367};
368
369// The data saved for comparing functions.
370template <typename T>
371class FuncDataT : public OrderedChangedData<BlockDataT<T>> {
372public:
373 FuncDataT(std::string S) : EntryBlockName(S) {}
374
375 // Return the name of the entry block
376 std::string getEntryBlockName() const { return EntryBlockName; }
377
378protected:
379 std::string EntryBlockName;
380};
381
382// The data saved for comparing IRs.
383template <typename T>
384class IRDataT : public OrderedChangedData<FuncDataT<T>> {};
385
386// Abstract template base class for a class that compares two IRs. The
387// class is created with the 2 IRs to compare and then compare is called.
388// The static function analyzeIR is used to build up the IR representation.
389template <typename T> class IRComparer {
390public:
391 IRComparer(const IRDataT<T> &Before, const IRDataT<T> &After)
392 : Before(Before), After(After) {}
393
394 // Compare the 2 IRs. \p handleFunctionCompare is called to handle the
395 // compare of a function. When \p InModule is set,
396 // this function is being handled as part of comparing a module.
397 void compare(
398 bool CompareModule,
399 std::function<void(bool InModule, unsigned Minor,
400 const FuncDataT<T> &Before, const FuncDataT<T> &After)>
401 CompareFunc);
402
403 // Analyze \p IR and build the IR representation in \p Data.
404 static void analyzeIR(Any IR, IRDataT<T> &Data);
405
406protected:
407 // Generate the data for \p F into \p Data.
408 static bool generateFunctionData(IRDataT<T> &Data, const Function &F);
409
410 const IRDataT<T> &Before;
411 const IRDataT<T> &After;
412};
413
414// A change printer that prints out in-line differences in the basic
415// blocks. It uses an InlineComparer to do the comparison so it shows
416// the differences prefixed with '-' and '+' for code that is removed
417// and added, respectively. Changes to the IR that do not affect basic
418// blocks are not reported as having changed the IR. The option
419// -print-module-scope does not affect this change reporter.
420class InLineChangePrinter : public TextChangeReporter<IRDataT<EmptyData>> {
421public:
422 InLineChangePrinter(bool VerboseMode, bool ColourMode)
423 : TextChangeReporter<IRDataT<EmptyData>>(VerboseMode),
424 UseColour(ColourMode) {}
425 ~InLineChangePrinter() override;
426 void registerCallbacks(PassInstrumentationCallbacks &PIC);
427
428protected:
429 // Create a representation of the IR.
430 void generateIRRepresentation(Any IR, StringRef PassID,
431 IRDataT<EmptyData> &Output) override;
432
433 // Called when an interesting IR has changed.
434 void handleAfter(StringRef PassID, std::string &Name,
435 const IRDataT<EmptyData> &Before,
436 const IRDataT<EmptyData> &After, Any) override;
437
438 void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
439 StringRef Divider, bool InModule, unsigned Minor,
440 const FuncDataT<EmptyData> &Before,
441 const FuncDataT<EmptyData> &After);
442
443 bool UseColour;
444};
445
446class VerifyInstrumentation {
447 bool DebugLogging;
448
449public:
450 VerifyInstrumentation(bool DebugLogging) : DebugLogging(DebugLogging) {}
451 void registerCallbacks(PassInstrumentationCallbacks &PIC);
452};
453
454/// This class implements --time-trace functionality for new pass manager.
455/// It provides the pass-instrumentation callbacks that measure the pass
456/// execution time. They collect time tracing info by TimeProfiler.
457class TimeProfilingPassesHandler {
458public:
459 TimeProfilingPassesHandler();
460 // We intend this to be unique per-compilation, thus no copies.
461 TimeProfilingPassesHandler(const TimeProfilingPassesHandler &) = delete;
462 void operator=(const TimeProfilingPassesHandler &) = delete;
463
464 void registerCallbacks(PassInstrumentationCallbacks &PIC);
465
466private:
467 // Implementation of pass instrumentation callbacks.
468 void runBeforePass(StringRef PassID, Any IR);
469 void runAfterPass();
470};
471
472// Class that holds transitions between basic blocks. The transitions
473// are contained in a map of values to names of basic blocks.
474class DCData {
475public:
476 // Fill the map with the transitions from basic block \p B.
477 DCData(const BasicBlock &B);
478
479 // Return an iterator to the names of the successor blocks.
480 StringMap<std::string>::const_iterator begin() const {
481 return Successors.begin();
482 }
483 StringMap<std::string>::const_iterator end() const {
484 return Successors.end();
485 }
486
487 // Return the label of the basic block reached on a transition on \p S.
488 StringRef getSuccessorLabel(StringRef S) const {
489 assert(Successors.count(S) == 1 && "Expected to find successor.");
490 return Successors.find(Key: S)->getValue();
491 }
492
493protected:
494 // Add a transition to \p Succ on \p Label
495 void addSuccessorLabel(StringRef Succ, StringRef Label) {
496 std::pair<std::string, std::string> SS{Succ.str(), Label.str()};
497 Successors.insert(KV: SS);
498 }
499
500 StringMap<std::string> Successors;
501};
502
503// A change reporter that builds a website with links to pdf files showing
504// dot control flow graphs with changed instructions shown in colour.
505class DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
506public:
507 DotCfgChangeReporter(bool Verbose);
508 ~DotCfgChangeReporter() override;
509 void registerCallbacks(PassInstrumentationCallbacks &PIC);
510
511protected:
512 // Initialize the HTML file and output the header.
513 bool initializeHTML();
514
515 // Called on the first IR processed.
516 void handleInitialIR(Any IR) override;
517 // Called before and after a pass to get the representation of the IR.
518 void generateIRRepresentation(Any IR, StringRef PassID,
519 IRDataT<DCData> &Output) override;
520 // Called when the pass is not iteresting.
521 void omitAfter(StringRef PassID, std::string &Name) override;
522 // Called when an interesting IR has changed.
523 void handleAfter(StringRef PassID, std::string &Name,
524 const IRDataT<DCData> &Before, const IRDataT<DCData> &After,
525 Any) override;
526 // Called when an interesting pass is invalidated.
527 void handleInvalidated(StringRef PassID) override;
528 // Called when the IR or pass is not interesting.
529 void handleFiltered(StringRef PassID, std::string &Name) override;
530 // Called when an ignored pass is encountered.
531 void handleIgnored(StringRef PassID, std::string &Name) override;
532
533 // Generate the pdf file into \p Dir / \p PDFFileName using \p DotFile as
534 // input and return the html <a> tag with \Text as the content.
535 static std::string genHTML(StringRef Text, StringRef DotFile,
536 StringRef PDFFileName);
537
538 void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
539 StringRef Divider, bool InModule, unsigned Minor,
540 const FuncDataT<DCData> &Before,
541 const FuncDataT<DCData> &After);
542
543 unsigned N = 0;
544 std::unique_ptr<raw_fd_ostream> HTML;
545};
546
547// Print IR on crash.
548class PrintCrashIRInstrumentation {
549public:
550 PrintCrashIRInstrumentation()
551 : SavedIR("*** Dump of IR Before Last Pass Unknown ***") {}
552 ~PrintCrashIRInstrumentation();
553 void registerCallbacks(PassInstrumentationCallbacks &PIC);
554 void reportCrashIR();
555
556protected:
557 std::string SavedIR;
558
559private:
560 // The crash reporter that will report on a crash.
561 static PrintCrashIRInstrumentation *CrashReporter;
562 // Crash handler registered when print-on-crash is specified.
563 static void SignalHandler(void *);
564};
565
566/// This class provides an interface to register all the standard pass
567/// instrumentations and manages their state (if any).
568class StandardInstrumentations {
569 PrintIRInstrumentation PrintIR;
570 PrintPassInstrumentation PrintPass;
571 TimePassesHandler TimePasses;
572 TimeProfilingPassesHandler TimeProfilingPasses;
573 OptNoneInstrumentation OptNone;
574 OptPassGateInstrumentation OptPassGate;
575 PreservedCFGCheckerInstrumentation PreservedCFGChecker;
576 IRChangedPrinter PrintChangedIR;
577 PseudoProbeVerifier PseudoProbeVerification;
578 InLineChangePrinter PrintChangedDiff;
579 DotCfgChangeReporter WebsiteChangeReporter;
580 PrintCrashIRInstrumentation PrintCrashIR;
581 IRChangedTester ChangeTester;
582 VerifyInstrumentation Verify;
583
584 bool VerifyEach;
585
586public:
587 StandardInstrumentations(LLVMContext &Context, bool DebugLogging,
588 bool VerifyEach = false,
589 PrintPassOptions PrintPassOpts = PrintPassOptions());
590
591 // Register all the standard instrumentation callbacks. If \p FAM is nullptr
592 // then PreservedCFGChecker is not enabled.
593 void registerCallbacks(PassInstrumentationCallbacks &PIC,
594 ModuleAnalysisManager *MAM = nullptr);
595
596 TimePassesHandler &getTimePasses() { return TimePasses; }
597};
598
599extern template class ChangeReporter<std::string>;
600extern template class TextChangeReporter<std::string>;
601
602extern template class BlockDataT<EmptyData>;
603extern template class FuncDataT<EmptyData>;
604extern template class IRDataT<EmptyData>;
605extern template class ChangeReporter<IRDataT<EmptyData>>;
606extern template class TextChangeReporter<IRDataT<EmptyData>>;
607extern template class IRComparer<EmptyData>;
608
609} // namespace llvm
610
611#endif
612

source code of llvm/include/llvm/Passes/StandardInstrumentations.h