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

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