1 //===- Standard pass instrumentations handling ----------------*- 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 file defines IR-printing pass instrumentation callbacks as well as
11 /// StandardInstrumentations class that manages standard pass instrumentations.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/Passes/StandardInstrumentations.h"
16 #include "llvm/ADT/Any.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Analysis/CallGraphSCCPass.h"
20 #include "llvm/Analysis/LazyCallGraph.h"
21 #include "llvm/Analysis/LoopInfo.h"
22 #include "llvm/IR/Function.h"
23 #include "llvm/IR/LegacyPassManager.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/IR/PassInstrumentation.h"
26 #include "llvm/IR/PassManager.h"
27 #include "llvm/IR/PrintPasses.h"
28 #include "llvm/IR/Verifier.h"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/FormatVariadic.h"
32 #include "llvm/Support/MemoryBuffer.h"
33 #include "llvm/Support/Program.h"
34 #include "llvm/Support/raw_ostream.h"
35 #include <unordered_set>
36 #include <vector>
37 
38 using namespace llvm;
39 
40 cl::opt<bool> PreservedCFGCheckerInstrumentation::VerifyPreservedCFG(
41     "verify-cfg-preserved", cl::Hidden,
42 #ifdef NDEBUG
43     cl::init(false));
44 #else
45     cl::init(true));
46 #endif
47 
48 // An option that prints out the IR after passes, similar to
49 // -print-after-all except that it only prints the IR after passes that
50 // change the IR.  Those passes that do not make changes to the IR are
51 // reported as not making any changes.  In addition, the initial IR is
52 // also reported.  Other hidden options affect the output from this
53 // option.  -filter-passes will limit the output to the named passes
54 // that actually change the IR and other passes are reported as filtered out.
55 // The specified passes will either be reported as making no changes (with
56 // no IR reported) or the changed IR will be reported.  Also, the
57 // -filter-print-funcs and -print-module-scope options will do similar
58 // filtering based on function name, reporting changed IRs as functions(or
59 // modules if -print-module-scope is specified) for a particular function
60 // or indicating that the IR has been filtered out.  The extra options
61 // can be combined, allowing only changed IRs for certain passes on certain
62 // functions to be reported in different formats, with the rest being
63 // reported as filtered out.  The -print-before-changed option will print
64 // the IR as it was before each pass that changed it.  The optional
65 // value of quiet will only report when the IR changes, suppressing
66 // all other messages, including the initial IR.  The values "diff" and
67 // "diff-quiet" will present the changes in a form similar to a patch, in
68 // either verbose or quiet mode, respectively.  The lines that are removed
69 // and added are prefixed with '-' and '+', respectively.  The
70 // -filter-print-funcs and -filter-passes can be used to filter the output.
71 // This reporter relies on the linux diff utility to do comparisons and
72 // insert the prefixes.  For systems that do not have the necessary
73 // facilities, the error message will be shown in place of the expected output.
74 //
75 enum class ChangePrinter {
76   NoChangePrinter,
77   PrintChangedVerbose,
78   PrintChangedQuiet,
79   PrintChangedDiffVerbose,
80   PrintChangedDiffQuiet,
81   PrintChangedColourDiffVerbose,
82   PrintChangedColourDiffQuiet
83 };
84 static cl::opt<ChangePrinter> PrintChanged(
85     "print-changed", cl::desc("Print changed IRs"), cl::Hidden,
86     cl::ValueOptional, cl::init(ChangePrinter::NoChangePrinter),
87     cl::values(
88         clEnumValN(ChangePrinter::PrintChangedQuiet, "quiet",
89                    "Run in quiet mode"),
90         clEnumValN(ChangePrinter::PrintChangedDiffVerbose, "diff",
91                    "Display patch-like changes"),
92         clEnumValN(ChangePrinter::PrintChangedDiffQuiet, "diff-quiet",
93                    "Display patch-like changes in quiet mode"),
94         clEnumValN(ChangePrinter::PrintChangedColourDiffVerbose, "cdiff",
95                    "Display patch-like changes with color"),
96         clEnumValN(ChangePrinter::PrintChangedColourDiffQuiet, "cdiff-quiet",
97                    "Display patch-like changes in quiet mode with color"),
98         // Sentinel value for unspecified option.
99         clEnumValN(ChangePrinter::PrintChangedVerbose, "", "")));
100 
101 // An option that supports the -print-changed option.  See
102 // the description for -print-changed for an explanation of the use
103 // of this option.  Note that this option has no effect without -print-changed.
104 static cl::list<std::string>
105     PrintPassesList("filter-passes", cl::value_desc("pass names"),
106                     cl::desc("Only consider IR changes for passes whose names "
107                              "match for the print-changed option"),
108                     cl::CommaSeparated, cl::Hidden);
109 // An option that supports the -print-changed option.  See
110 // the description for -print-changed for an explanation of the use
111 // of this option.  Note that this option has no effect without -print-changed.
112 static cl::opt<bool>
113     PrintChangedBefore("print-before-changed",
114                        cl::desc("Print before passes that change them"),
115                        cl::init(false), cl::Hidden);
116 
117 // An option for specifying the diff used by print-changed=[diff | diff-quiet]
118 static cl::opt<std::string>
119     DiffBinary("print-changed-diff-path", cl::Hidden, cl::init("diff"),
120                cl::desc("system diff used by change reporters"));
121 
122 namespace {
123 
124 // Perform a system based diff between \p Before and \p After, using
125 // \p OldLineFormat, \p NewLineFormat, and \p UnchangedLineFormat
126 // to control the formatting of the output.  Return an error message
127 // for any failures instead of the diff.
doSystemDiff(StringRef Before,StringRef After,StringRef OldLineFormat,StringRef NewLineFormat,StringRef UnchangedLineFormat)128 std::string doSystemDiff(StringRef Before, StringRef After,
129                          StringRef OldLineFormat, StringRef NewLineFormat,
130                          StringRef UnchangedLineFormat) {
131   StringRef SR[2]{Before, After};
132   // Store the 2 bodies into temporary files and call diff on them
133   // to get the body of the node.
134   const unsigned NumFiles = 3;
135   static std::string FileName[NumFiles];
136   static int FD[NumFiles]{-1, -1, -1};
137   for (unsigned I = 0; I < NumFiles; ++I) {
138     if (FD[I] == -1) {
139       SmallVector<char, 200> SV;
140       std::error_code EC =
141           sys::fs::createTemporaryFile("tmpdiff", "txt", FD[I], SV);
142       if (EC)
143         return "Unable to create temporary file.";
144       FileName[I] = Twine(SV).str();
145     }
146     // The third file is used as the result of the diff.
147     if (I == NumFiles - 1)
148       break;
149 
150     std::error_code EC = sys::fs::openFileForWrite(FileName[I], FD[I]);
151     if (EC)
152       return "Unable to open temporary file for writing.";
153 
154     raw_fd_ostream OutStream(FD[I], /*shouldClose=*/true);
155     if (FD[I] == -1)
156       return "Error opening file for writing.";
157     OutStream << SR[I];
158   }
159 
160   static ErrorOr<std::string> DiffExe = sys::findProgramByName(DiffBinary);
161   if (!DiffExe)
162     return "Unable to find diff executable.";
163 
164   SmallString<128> OLF = formatv("--old-line-format={0}", OldLineFormat);
165   SmallString<128> NLF = formatv("--new-line-format={0}", NewLineFormat);
166   SmallString<128> ULF =
167       formatv("--unchanged-line-format={0}", UnchangedLineFormat);
168 
169   StringRef Args[] = {"-w", "-d", OLF, NLF, ULF, FileName[0], FileName[1]};
170   Optional<StringRef> Redirects[] = {None, StringRef(FileName[2]), None};
171   int Result = sys::ExecuteAndWait(*DiffExe, Args, None, Redirects);
172   if (Result < 0)
173     return "Error executing system diff.";
174   std::string Diff;
175   auto B = MemoryBuffer::getFile(FileName[2]);
176   if (B && *B)
177     Diff = (*B)->getBuffer().str();
178   else
179     return "Unable to read result.";
180 
181   // Clean up.
182   for (unsigned I = 0; I < NumFiles; ++I) {
183     std::error_code EC = sys::fs::remove(FileName[I]);
184     if (EC)
185       return "Unable to remove temporary file.";
186   }
187   return Diff;
188 }
189 
190 /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
191 /// certain global filters. Will never return nullptr if \p Force is true.
unwrapModule(Any IR,bool Force=false)192 const Module *unwrapModule(Any IR, bool Force = false) {
193   if (any_isa<const Module *>(IR))
194     return any_cast<const Module *>(IR);
195 
196   if (any_isa<const Function *>(IR)) {
197     const Function *F = any_cast<const Function *>(IR);
198     if (!Force && !isFunctionInPrintList(F->getName()))
199       return nullptr;
200 
201     return F->getParent();
202   }
203 
204   if (any_isa<const LazyCallGraph::SCC *>(IR)) {
205     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
206     for (const LazyCallGraph::Node &N : *C) {
207       const Function &F = N.getFunction();
208       if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
209         return F.getParent();
210       }
211     }
212     assert(!Force && "Expected a module");
213     return nullptr;
214   }
215 
216   if (any_isa<const Loop *>(IR)) {
217     const Loop *L = any_cast<const Loop *>(IR);
218     const Function *F = L->getHeader()->getParent();
219     if (!Force && !isFunctionInPrintList(F->getName()))
220       return nullptr;
221     return F->getParent();
222   }
223 
224   llvm_unreachable("Unknown IR unit");
225 }
226 
printIR(raw_ostream & OS,const Function * F)227 void printIR(raw_ostream &OS, const Function *F) {
228   if (!isFunctionInPrintList(F->getName()))
229     return;
230   OS << *F;
231 }
232 
printIR(raw_ostream & OS,const Module * M)233 void printIR(raw_ostream &OS, const Module *M) {
234   if (isFunctionInPrintList("*") || forcePrintModuleIR()) {
235     M->print(OS, nullptr);
236   } else {
237     for (const auto &F : M->functions()) {
238       printIR(OS, &F);
239     }
240   }
241 }
242 
printIR(raw_ostream & OS,const LazyCallGraph::SCC * C)243 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
244   for (const LazyCallGraph::Node &N : *C) {
245     const Function &F = N.getFunction();
246     if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
247       F.print(OS);
248     }
249   }
250 }
251 
printIR(raw_ostream & OS,const Loop * L)252 void printIR(raw_ostream &OS, const Loop *L) {
253   const Function *F = L->getHeader()->getParent();
254   if (!isFunctionInPrintList(F->getName()))
255     return;
256   printLoop(const_cast<Loop &>(*L), OS);
257 }
258 
getIRName(Any IR)259 std::string getIRName(Any IR) {
260   if (any_isa<const Module *>(IR))
261     return "[module]";
262 
263   if (any_isa<const Function *>(IR)) {
264     const Function *F = any_cast<const Function *>(IR);
265     return F->getName().str();
266   }
267 
268   if (any_isa<const LazyCallGraph::SCC *>(IR)) {
269     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
270     return C->getName();
271   }
272 
273   if (any_isa<const Loop *>(IR)) {
274     const Loop *L = any_cast<const Loop *>(IR);
275     std::string S;
276     raw_string_ostream OS(S);
277     L->print(OS, /*Verbose*/ false, /*PrintNested*/ false);
278     return OS.str();
279   }
280 
281   llvm_unreachable("Unknown wrapped IR type");
282 }
283 
moduleContainsFilterPrintFunc(const Module & M)284 bool moduleContainsFilterPrintFunc(const Module &M) {
285   return any_of(M.functions(),
286                 [](const Function &F) {
287                   return isFunctionInPrintList(F.getName());
288                 }) ||
289          isFunctionInPrintList("*");
290 }
291 
sccContainsFilterPrintFunc(const LazyCallGraph::SCC & C)292 bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
293   return any_of(C,
294                 [](const LazyCallGraph::Node &N) {
295                   return isFunctionInPrintList(N.getName());
296                 }) ||
297          isFunctionInPrintList("*");
298 }
299 
shouldPrintIR(Any IR)300 bool shouldPrintIR(Any IR) {
301   if (any_isa<const Module *>(IR)) {
302     const Module *M = any_cast<const Module *>(IR);
303     return moduleContainsFilterPrintFunc(*M);
304   }
305 
306   if (any_isa<const Function *>(IR)) {
307     const Function *F = any_cast<const Function *>(IR);
308     return isFunctionInPrintList(F->getName());
309   }
310 
311   if (any_isa<const LazyCallGraph::SCC *>(IR)) {
312     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
313     return sccContainsFilterPrintFunc(*C);
314   }
315 
316   if (any_isa<const Loop *>(IR)) {
317     const Loop *L = any_cast<const Loop *>(IR);
318     return isFunctionInPrintList(L->getHeader()->getParent()->getName());
319   }
320   llvm_unreachable("Unknown wrapped IR type");
321 }
322 
323 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
324 /// llvm::Any and does actual print job.
unwrapAndPrint(raw_ostream & OS,Any IR)325 void unwrapAndPrint(raw_ostream &OS, Any IR) {
326   if (!shouldPrintIR(IR))
327     return;
328 
329   if (forcePrintModuleIR()) {
330     auto *M = unwrapModule(IR);
331     assert(M && "should have unwrapped module");
332     printIR(OS, M);
333     return;
334   }
335 
336   if (any_isa<const Module *>(IR)) {
337     const Module *M = any_cast<const Module *>(IR);
338     printIR(OS, M);
339     return;
340   }
341 
342   if (any_isa<const Function *>(IR)) {
343     const Function *F = any_cast<const Function *>(IR);
344     printIR(OS, F);
345     return;
346   }
347 
348   if (any_isa<const LazyCallGraph::SCC *>(IR)) {
349     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
350     printIR(OS, C);
351     return;
352   }
353 
354   if (any_isa<const Loop *>(IR)) {
355     const Loop *L = any_cast<const Loop *>(IR);
356     printIR(OS, L);
357     return;
358   }
359   llvm_unreachable("Unknown wrapped IR type");
360 }
361 
362 // Return true when this is a pass for which changes should be ignored
isIgnored(StringRef PassID)363 bool isIgnored(StringRef PassID) {
364   return isSpecialPass(PassID,
365                        {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
366                         "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass"});
367 }
368 
369 } // namespace
370 
371 template <typename IRUnitT>
~ChangeReporter()372 ChangeReporter<IRUnitT>::~ChangeReporter<IRUnitT>() {
373   assert(BeforeStack.empty() && "Problem with Change Printer stack.");
374 }
375 
376 template <typename IRUnitT>
isInterestingFunction(const Function & F)377 bool ChangeReporter<IRUnitT>::isInterestingFunction(const Function &F) {
378   return isFunctionInPrintList(F.getName());
379 }
380 
381 template <typename IRUnitT>
isInterestingPass(StringRef PassID)382 bool ChangeReporter<IRUnitT>::isInterestingPass(StringRef PassID) {
383   if (isIgnored(PassID))
384     return false;
385 
386   static std::unordered_set<std::string> PrintPassNames(PrintPassesList.begin(),
387                                                         PrintPassesList.end());
388   return PrintPassNames.empty() || PrintPassNames.count(PassID.str());
389 }
390 
391 // Return true when this is a pass on IR for which printing
392 // of changes is desired.
393 template <typename IRUnitT>
isInteresting(Any IR,StringRef PassID)394 bool ChangeReporter<IRUnitT>::isInteresting(Any IR, StringRef PassID) {
395   if (!isInterestingPass(PassID))
396     return false;
397   if (any_isa<const Function *>(IR))
398     return isInterestingFunction(*any_cast<const Function *>(IR));
399   return true;
400 }
401 
402 template <typename IRUnitT>
saveIRBeforePass(Any IR,StringRef PassID)403 void ChangeReporter<IRUnitT>::saveIRBeforePass(Any IR, StringRef PassID) {
404   // Always need to place something on the stack because invalidated passes
405   // are not given the IR so it cannot be determined whether the pass was for
406   // something that was filtered out.
407   BeforeStack.emplace_back();
408 
409   if (!isInteresting(IR, PassID))
410     return;
411   // Is this the initial IR?
412   if (InitialIR) {
413     InitialIR = false;
414     if (VerboseMode)
415       handleInitialIR(IR);
416   }
417 
418   // Save the IR representation on the stack.
419   IRUnitT &Data = BeforeStack.back();
420   generateIRRepresentation(IR, PassID, Data);
421 }
422 
423 template <typename IRUnitT>
handleIRAfterPass(Any IR,StringRef PassID)424 void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) {
425   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
426 
427   std::string Name = getIRName(IR);
428 
429   if (isIgnored(PassID)) {
430     if (VerboseMode)
431       handleIgnored(PassID, Name);
432   } else if (!isInteresting(IR, PassID)) {
433     if (VerboseMode)
434       handleFiltered(PassID, Name);
435   } else {
436     // Get the before rep from the stack
437     IRUnitT &Before = BeforeStack.back();
438     // Create the after rep
439     IRUnitT After;
440     generateIRRepresentation(IR, PassID, After);
441 
442     // Was there a change in IR?
443     if (same(Before, After)) {
444       if (VerboseMode)
445         omitAfter(PassID, Name);
446     } else
447       handleAfter(PassID, Name, Before, After, IR);
448   }
449   BeforeStack.pop_back();
450 }
451 
452 template <typename IRUnitT>
handleInvalidatedPass(StringRef PassID)453 void ChangeReporter<IRUnitT>::handleInvalidatedPass(StringRef PassID) {
454   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
455 
456   // Always flag it as invalidated as we cannot determine when
457   // a pass for a filtered function is invalidated since we do not
458   // get the IR in the call.  Also, the output is just alternate
459   // forms of the banner anyway.
460   if (VerboseMode)
461     handleInvalidated(PassID);
462   BeforeStack.pop_back();
463 }
464 
465 template <typename IRUnitT>
registerRequiredCallbacks(PassInstrumentationCallbacks & PIC)466 void ChangeReporter<IRUnitT>::registerRequiredCallbacks(
467     PassInstrumentationCallbacks &PIC) {
468   PIC.registerBeforeNonSkippedPassCallback(
469       [this](StringRef P, Any IR) { saveIRBeforePass(IR, P); });
470 
471   PIC.registerAfterPassCallback(
472       [this](StringRef P, Any IR, const PreservedAnalyses &) {
473         handleIRAfterPass(IR, P);
474       });
475   PIC.registerAfterPassInvalidatedCallback(
476       [this](StringRef P, const PreservedAnalyses &) {
477         handleInvalidatedPass(P);
478       });
479 }
480 
ChangedBlockData(const BasicBlock & B)481 ChangedBlockData::ChangedBlockData(const BasicBlock &B)
482     : Label(B.getName().str()) {
483   raw_string_ostream SS(Body);
484   B.print(SS, nullptr, true, true);
485 }
486 
487 template <typename IRUnitT>
TextChangeReporter(bool Verbose)488 TextChangeReporter<IRUnitT>::TextChangeReporter(bool Verbose)
489     : ChangeReporter<IRUnitT>(Verbose), Out(dbgs()) {}
490 
491 template <typename IRUnitT>
handleInitialIR(Any IR)492 void TextChangeReporter<IRUnitT>::handleInitialIR(Any IR) {
493   // Always print the module.
494   // Unwrap and print directly to avoid filtering problems in general routines.
495   auto *M = unwrapModule(IR, /*Force=*/true);
496   assert(M && "Expected module to be unwrapped when forced.");
497   Out << "*** IR Dump At Start ***\n";
498   M->print(Out, nullptr);
499 }
500 
501 template <typename IRUnitT>
omitAfter(StringRef PassID,std::string & Name)502 void TextChangeReporter<IRUnitT>::omitAfter(StringRef PassID,
503                                             std::string &Name) {
504   Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
505                  PassID, Name);
506 }
507 
508 template <typename IRUnitT>
handleInvalidated(StringRef PassID)509 void TextChangeReporter<IRUnitT>::handleInvalidated(StringRef PassID) {
510   Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
511 }
512 
513 template <typename IRUnitT>
handleFiltered(StringRef PassID,std::string & Name)514 void TextChangeReporter<IRUnitT>::handleFiltered(StringRef PassID,
515                                                  std::string &Name) {
516   SmallString<20> Banner =
517       formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
518   Out << Banner;
519 }
520 
521 template <typename IRUnitT>
handleIgnored(StringRef PassID,std::string & Name)522 void TextChangeReporter<IRUnitT>::handleIgnored(StringRef PassID,
523                                                 std::string &Name) {
524   Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
525 }
526 
~IRChangedPrinter()527 IRChangedPrinter::~IRChangedPrinter() {}
528 
registerCallbacks(PassInstrumentationCallbacks & PIC)529 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
530   if (PrintChanged == ChangePrinter::PrintChangedVerbose ||
531       PrintChanged == ChangePrinter::PrintChangedQuiet)
532     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
533 }
534 
generateIRRepresentation(Any IR,StringRef PassID,std::string & Output)535 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID,
536                                                 std::string &Output) {
537   raw_string_ostream OS(Output);
538   unwrapAndPrint(OS, IR);
539   OS.str();
540 }
541 
handleAfter(StringRef PassID,std::string & Name,const std::string & Before,const std::string & After,Any)542 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
543                                    const std::string &Before,
544                                    const std::string &After, Any) {
545   // Report the IR before the changes when requested.
546   if (PrintChangedBefore)
547     Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
548         << Before;
549 
550   // We might not get anything to print if we only want to print a specific
551   // function but it gets deleted.
552   if (After.empty()) {
553     Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
554     return;
555   }
556 
557   Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
558 }
559 
same(const std::string & S1,const std::string & S2)560 bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) {
561   return S1 == S2;
562 }
563 
564 template <typename IRData>
report(const OrderedChangedData & Before,const OrderedChangedData & After,function_ref<void (const IRData *,const IRData *)> HandlePair)565 void OrderedChangedData<IRData>::report(
566     const OrderedChangedData &Before, const OrderedChangedData &After,
567     function_ref<void(const IRData *, const IRData *)> HandlePair) {
568   const auto &BFD = Before.getData();
569   const auto &AFD = After.getData();
570   std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
571   std::vector<std::string>::const_iterator BE = Before.getOrder().end();
572   std::vector<std::string>::const_iterator AI = After.getOrder().begin();
573   std::vector<std::string>::const_iterator AE = After.getOrder().end();
574 
575   auto handlePotentiallyRemovedIRData = [&](std::string S) {
576     // The order in LLVM may have changed so check if still exists.
577     if (!AFD.count(S)) {
578       // This has been removed.
579       HandlePair(&BFD.find(*BI)->getValue(), nullptr);
580     }
581   };
582   auto handleNewIRData = [&](std::vector<const IRData *> &Q) {
583     // Print out any queued up new sections
584     for (const IRData *NBI : Q)
585       HandlePair(nullptr, NBI);
586     Q.clear();
587   };
588 
589   // Print out the IRData in the after order, with before ones interspersed
590   // appropriately (ie, somewhere near where they were in the before list).
591   // Start at the beginning of both lists.  Loop through the
592   // after list.  If an element is common, then advance in the before list
593   // reporting the removed ones until the common one is reached.  Report any
594   // queued up new ones and then report the common one.  If an element is not
595   // common, then enqueue it for reporting.  When the after list is exhausted,
596   // loop through the before list, reporting any removed ones.  Finally,
597   // report the rest of the enqueued new ones.
598   std::vector<const IRData *> NewIRDataQueue;
599   while (AI != AE) {
600     if (!BFD.count(*AI)) {
601       // This section is new so place it in the queue.  This will cause it
602       // to be reported after deleted sections.
603       NewIRDataQueue.emplace_back(&AFD.find(*AI)->getValue());
604       ++AI;
605       continue;
606     }
607     // This section is in both; advance and print out any before-only
608     // until we get to it.
609     while (*BI != *AI) {
610       handlePotentiallyRemovedIRData(*BI);
611       ++BI;
612     }
613     // Report any new sections that were queued up and waiting.
614     handleNewIRData(NewIRDataQueue);
615 
616     const IRData &AData = AFD.find(*AI)->getValue();
617     const IRData &BData = BFD.find(*AI)->getValue();
618     HandlePair(&BData, &AData);
619     ++BI;
620     ++AI;
621   }
622 
623   // Check any remaining before sections to see if they have been removed
624   while (BI != BE) {
625     handlePotentiallyRemovedIRData(*BI);
626     ++BI;
627   }
628 
629   handleNewIRData(NewIRDataQueue);
630 }
631 
compare(Any IR,StringRef Prefix,StringRef PassID,StringRef Name)632 void ChangedIRComparer::compare(Any IR, StringRef Prefix, StringRef PassID,
633                                 StringRef Name) {
634   if (!getModuleForComparison(IR)) {
635     // Not a module so just handle the single function.
636     assert(Before.getData().size() == 1 && "Expected only one function.");
637     assert(After.getData().size() == 1 && "Expected only one function.");
638     handleFunctionCompare(Name, Prefix, PassID, false,
639                           Before.getData().begin()->getValue(),
640                           After.getData().begin()->getValue());
641     return;
642   }
643 
644   ChangedIRData::report(
645       Before, After, [&](const ChangedFuncData *B, const ChangedFuncData *A) {
646         assert((B || A) && "Both functions cannot be missing.");
647         ChangedFuncData Missing;
648         if (!B)
649           B = &Missing;
650         else if (!A)
651           A = &Missing;
652         handleFunctionCompare(Name, Prefix, PassID, true, *B, *A);
653       });
654 }
655 
analyzeIR(Any IR,ChangedIRData & Data)656 void ChangedIRComparer::analyzeIR(Any IR, ChangedIRData &Data) {
657   if (const Module *M = getModuleForComparison(IR)) {
658     // Create data for each existing/interesting function in the module.
659     for (const Function &F : *M)
660       generateFunctionData(Data, F);
661     return;
662   }
663 
664   const Function *F = nullptr;
665   if (any_isa<const Function *>(IR))
666     F = any_cast<const Function *>(IR);
667   else {
668     assert(any_isa<const Loop *>(IR) && "Unknown IR unit.");
669     const Loop *L = any_cast<const Loop *>(IR);
670     F = L->getHeader()->getParent();
671   }
672   assert(F && "Unknown IR unit.");
673   generateFunctionData(Data, *F);
674 }
675 
getModuleForComparison(Any IR)676 const Module *ChangedIRComparer::getModuleForComparison(Any IR) {
677   if (any_isa<const Module *>(IR))
678     return any_cast<const Module *>(IR);
679   if (any_isa<const LazyCallGraph::SCC *>(IR))
680     return any_cast<const LazyCallGraph::SCC *>(IR)
681         ->begin()
682         ->getFunction()
683         .getParent();
684   return nullptr;
685 }
686 
generateFunctionData(ChangedIRData & Data,const Function & F)687 bool ChangedIRComparer::generateFunctionData(ChangedIRData &Data,
688                                              const Function &F) {
689   if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
690     ChangedFuncData CFD;
691     for (const auto &B : F) {
692       CFD.getOrder().emplace_back(B.getName());
693       CFD.getData().insert({B.getName(), B});
694     }
695     Data.getOrder().emplace_back(F.getName());
696     Data.getData().insert({F.getName(), CFD});
697     return true;
698   }
699   return false;
700 }
701 
~PrintIRInstrumentation()702 PrintIRInstrumentation::~PrintIRInstrumentation() {
703   assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
704 }
705 
pushModuleDesc(StringRef PassID,Any IR)706 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) {
707   const Module *M = unwrapModule(IR);
708   ModuleDescStack.emplace_back(M, getIRName(IR), PassID);
709 }
710 
711 PrintIRInstrumentation::PrintModuleDesc
popModuleDesc(StringRef PassID)712 PrintIRInstrumentation::popModuleDesc(StringRef PassID) {
713   assert(!ModuleDescStack.empty() && "empty ModuleDescStack");
714   PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val();
715   assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack");
716   return ModuleDesc;
717 }
718 
printBeforePass(StringRef PassID,Any IR)719 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
720   if (isIgnored(PassID))
721     return;
722 
723   // Saving Module for AfterPassInvalidated operations.
724   // Note: here we rely on a fact that we do not change modules while
725   // traversing the pipeline, so the latest captured module is good
726   // for all print operations that has not happen yet.
727   if (shouldPrintAfterPass(PassID))
728     pushModuleDesc(PassID, IR);
729 
730   if (!shouldPrintBeforePass(PassID))
731     return;
732 
733   if (!shouldPrintIR(IR))
734     return;
735 
736   dbgs() << "*** IR Dump Before " << PassID << " on " << getIRName(IR)
737          << " ***\n";
738   unwrapAndPrint(dbgs(), IR);
739 }
740 
printAfterPass(StringRef PassID,Any IR)741 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
742   if (isIgnored(PassID))
743     return;
744 
745   if (!shouldPrintAfterPass(PassID))
746     return;
747 
748   const Module *M;
749   std::string IRName;
750   StringRef StoredPassID;
751   std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID);
752   assert(StoredPassID == PassID && "mismatched PassID");
753 
754   if (!shouldPrintIR(IR))
755     return;
756 
757   dbgs() << "*** IR Dump After " << PassID << " on " << IRName << " ***\n";
758   unwrapAndPrint(dbgs(), IR);
759 }
760 
printAfterPassInvalidated(StringRef PassID)761 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
762   StringRef PassName = PIC->getPassNameForClassName(PassID);
763   if (!shouldPrintAfterPass(PassName))
764     return;
765 
766   if (isIgnored(PassID))
767     return;
768 
769   const Module *M;
770   std::string IRName;
771   StringRef StoredPassID;
772   std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID);
773   assert(StoredPassID == PassID && "mismatched PassID");
774   // Additional filtering (e.g. -filter-print-func) can lead to module
775   // printing being skipped.
776   if (!M)
777     return;
778 
779   SmallString<20> Banner =
780       formatv("*** IR Dump After {0} on {1} (invalidated) ***", PassID, IRName);
781   dbgs() << Banner << "\n";
782   printIR(dbgs(), M);
783 }
784 
shouldPrintBeforePass(StringRef PassID)785 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
786   if (shouldPrintBeforeAll())
787     return true;
788 
789   StringRef PassName = PIC->getPassNameForClassName(PassID);
790   return llvm::is_contained(printBeforePasses(), PassName);
791 }
792 
shouldPrintAfterPass(StringRef PassID)793 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
794   if (shouldPrintAfterAll())
795     return true;
796 
797   StringRef PassName = PIC->getPassNameForClassName(PassID);
798   return llvm::is_contained(printAfterPasses(), PassName);
799 }
800 
registerCallbacks(PassInstrumentationCallbacks & PIC)801 void PrintIRInstrumentation::registerCallbacks(
802     PassInstrumentationCallbacks &PIC) {
803   this->PIC = &PIC;
804 
805   // BeforePass callback is not just for printing, it also saves a Module
806   // for later use in AfterPassInvalidated.
807   if (shouldPrintBeforeSomePass() || shouldPrintAfterSomePass())
808     PIC.registerBeforeNonSkippedPassCallback(
809         [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
810 
811   if (shouldPrintAfterSomePass()) {
812     PIC.registerAfterPassCallback(
813         [this](StringRef P, Any IR, const PreservedAnalyses &) {
814           this->printAfterPass(P, IR);
815         });
816     PIC.registerAfterPassInvalidatedCallback(
817         [this](StringRef P, const PreservedAnalyses &) {
818           this->printAfterPassInvalidated(P);
819         });
820   }
821 }
822 
registerCallbacks(PassInstrumentationCallbacks & PIC)823 void OptNoneInstrumentation::registerCallbacks(
824     PassInstrumentationCallbacks &PIC) {
825   PIC.registerShouldRunOptionalPassCallback(
826       [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
827 }
828 
shouldRun(StringRef PassID,Any IR)829 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
830   const Function *F = nullptr;
831   if (any_isa<const Function *>(IR)) {
832     F = any_cast<const Function *>(IR);
833   } else if (any_isa<const Loop *>(IR)) {
834     F = any_cast<const Loop *>(IR)->getHeader()->getParent();
835   }
836   bool ShouldRun = !(F && F->hasOptNone());
837   if (!ShouldRun && DebugLogging) {
838     errs() << "Skipping pass " << PassID << " on " << F->getName()
839            << " due to optnone attribute\n";
840   }
841   return ShouldRun;
842 }
843 
registerCallbacks(PassInstrumentationCallbacks & PIC)844 void OptBisectInstrumentation::registerCallbacks(
845     PassInstrumentationCallbacks &PIC) {
846   if (!OptBisector->isEnabled())
847     return;
848   PIC.registerShouldRunOptionalPassCallback([](StringRef PassID, Any IR) {
849     return isIgnored(PassID) || OptBisector->checkPass(PassID, getIRName(IR));
850   });
851 }
852 
print()853 raw_ostream &PrintPassInstrumentation::print() {
854   if (Opts.Indent) {
855     assert(Indent >= 0);
856     dbgs().indent(Indent);
857   }
858   return dbgs();
859 }
860 
registerCallbacks(PassInstrumentationCallbacks & PIC)861 void PrintPassInstrumentation::registerCallbacks(
862     PassInstrumentationCallbacks &PIC) {
863   if (!Enabled)
864     return;
865 
866   std::vector<StringRef> SpecialPasses;
867   if (!Opts.Verbose) {
868     SpecialPasses.emplace_back("PassManager");
869     SpecialPasses.emplace_back("PassAdaptor");
870   }
871 
872   PIC.registerBeforeSkippedPassCallback(
873       [this, SpecialPasses](StringRef PassID, Any IR) {
874         assert(!isSpecialPass(PassID, SpecialPasses) &&
875                "Unexpectedly skipping special pass");
876 
877         print() << "Skipping pass: " << PassID << " on " << getIRName(IR)
878                 << "\n";
879       });
880   PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
881                                                StringRef PassID, Any IR) {
882     if (isSpecialPass(PassID, SpecialPasses))
883       return;
884 
885     print() << "Running pass: " << PassID << " on " << getIRName(IR) << "\n";
886     Indent += 2;
887   });
888   PIC.registerAfterPassCallback(
889       [this, SpecialPasses](StringRef PassID, Any IR,
890                             const PreservedAnalyses &) {
891         if (isSpecialPass(PassID, SpecialPasses))
892           return;
893 
894         Indent -= 2;
895       });
896   PIC.registerAfterPassInvalidatedCallback(
897       [this, SpecialPasses](StringRef PassID, Any IR) {
898         if (isSpecialPass(PassID, SpecialPasses))
899           return;
900 
901         Indent -= 2;
902       });
903 
904   if (!Opts.SkipAnalyses) {
905     PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) {
906       print() << "Running analysis: " << PassID << " on " << getIRName(IR)
907               << "\n";
908       Indent += 2;
909     });
910     PIC.registerAfterAnalysisCallback(
911         [this](StringRef PassID, Any IR) { Indent -= 2; });
912     PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) {
913       print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
914               << "\n";
915     });
916     PIC.registerAnalysesClearedCallback([this](StringRef IRName) {
917       print() << "Clearing all analysis results for: " << IRName << "\n";
918     });
919   }
920 }
921 
CFG(const Function * F,bool TrackBBLifetime)922 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F,
923                                              bool TrackBBLifetime) {
924   if (TrackBBLifetime)
925     BBGuards = DenseMap<intptr_t, BBGuard>(F->size());
926   for (const auto &BB : *F) {
927     if (BBGuards)
928       BBGuards->try_emplace(intptr_t(&BB), &BB);
929     for (auto *Succ : successors(&BB)) {
930       Graph[&BB][Succ]++;
931       if (BBGuards)
932         BBGuards->try_emplace(intptr_t(Succ), Succ);
933     }
934   }
935 }
936 
printBBName(raw_ostream & out,const BasicBlock * BB)937 static void printBBName(raw_ostream &out, const BasicBlock *BB) {
938   if (BB->hasName()) {
939     out << BB->getName() << "<" << BB << ">";
940     return;
941   }
942 
943   if (!BB->getParent()) {
944     out << "unnamed_removed<" << BB << ">";
945     return;
946   }
947 
948   if (BB->isEntryBlock()) {
949     out << "entry"
950         << "<" << BB << ">";
951     return;
952   }
953 
954   unsigned FuncOrderBlockNum = 0;
955   for (auto &FuncBB : *BB->getParent()) {
956     if (&FuncBB == BB)
957       break;
958     FuncOrderBlockNum++;
959   }
960   out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
961 }
962 
printDiff(raw_ostream & out,const CFG & Before,const CFG & After)963 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out,
964                                                         const CFG &Before,
965                                                         const CFG &After) {
966   assert(!After.isPoisoned());
967   if (Before.isPoisoned()) {
968     out << "Some blocks were deleted\n";
969     return;
970   }
971 
972   // Find and print graph differences.
973   if (Before.Graph.size() != After.Graph.size())
974     out << "Different number of non-leaf basic blocks: before="
975         << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
976 
977   for (auto &BB : Before.Graph) {
978     auto BA = After.Graph.find(BB.first);
979     if (BA == After.Graph.end()) {
980       out << "Non-leaf block ";
981       printBBName(out, BB.first);
982       out << " is removed (" << BB.second.size() << " successors)\n";
983     }
984   }
985 
986   for (auto &BA : After.Graph) {
987     auto BB = Before.Graph.find(BA.first);
988     if (BB == Before.Graph.end()) {
989       out << "Non-leaf block ";
990       printBBName(out, BA.first);
991       out << " is added (" << BA.second.size() << " successors)\n";
992       continue;
993     }
994 
995     if (BB->second == BA.second)
996       continue;
997 
998     out << "Different successors of block ";
999     printBBName(out, BA.first);
1000     out << " (unordered):\n";
1001     out << "- before (" << BB->second.size() << "): ";
1002     for (auto &SuccB : BB->second) {
1003       printBBName(out, SuccB.first);
1004       if (SuccB.second != 1)
1005         out << "(" << SuccB.second << "), ";
1006       else
1007         out << ", ";
1008     }
1009     out << "\n";
1010     out << "- after (" << BA.second.size() << "): ";
1011     for (auto &SuccA : BA.second) {
1012       printBBName(out, SuccA.first);
1013       if (SuccA.second != 1)
1014         out << "(" << SuccA.second << "), ";
1015       else
1016         out << ", ";
1017     }
1018     out << "\n";
1019   }
1020 }
1021 
1022 // PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1023 // passes, that reported they kept CFG analyses up-to-date, did not actually
1024 // change CFG. This check is done as follows. Before every functional pass in
1025 // BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1026 // PreservedCFGCheckerInstrumentation::CFG) is requested from
1027 // FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1028 // functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1029 // up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1030 // available) is checked to be equal to a freshly created CFG snapshot.
1031 struct PreservedCFGCheckerAnalysis
1032     : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1033   friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>;
1034 
1035   static AnalysisKey Key;
1036 
1037 public:
1038   /// Provide the result type for this analysis pass.
1039   using Result = PreservedCFGCheckerInstrumentation::CFG;
1040 
1041   /// Run the analysis pass over a function and produce CFG.
runPreservedCFGCheckerAnalysis1042   Result run(Function &F, FunctionAnalysisManager &FAM) {
1043     return Result(&F, /* TrackBBLifetime */ true);
1044   }
1045 };
1046 
1047 AnalysisKey PreservedCFGCheckerAnalysis::Key;
1048 
invalidate(Function & F,const PreservedAnalyses & PA,FunctionAnalysisManager::Invalidator &)1049 bool PreservedCFGCheckerInstrumentation::CFG::invalidate(
1050     Function &F, const PreservedAnalyses &PA,
1051     FunctionAnalysisManager::Invalidator &) {
1052   auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1053   return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1054            PAC.preservedSet<CFGAnalyses>());
1055 }
1056 
registerCallbacks(PassInstrumentationCallbacks & PIC,FunctionAnalysisManager & FAM)1057 void PreservedCFGCheckerInstrumentation::registerCallbacks(
1058     PassInstrumentationCallbacks &PIC, FunctionAnalysisManager &FAM) {
1059   if (!VerifyPreservedCFG)
1060     return;
1061 
1062   FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1063 
1064   auto checkCFG = [](StringRef Pass, StringRef FuncName, const CFG &GraphBefore,
1065                      const CFG &GraphAfter) {
1066     if (GraphAfter == GraphBefore)
1067       return;
1068 
1069     dbgs() << "Error: " << Pass
1070            << " does not invalidate CFG analyses but CFG changes detected in "
1071               "function @"
1072            << FuncName << ":\n";
1073     CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1074     report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1075   };
1076 
1077   PIC.registerBeforeNonSkippedPassCallback(
1078       [this, &FAM](StringRef P, Any IR) {
1079 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1080         assert(&PassStack.emplace_back(P));
1081 #endif
1082         (void)this;
1083         if (!any_isa<const Function *>(IR))
1084           return;
1085 
1086         const auto *F = any_cast<const Function *>(IR);
1087         // Make sure a fresh CFG snapshot is available before the pass.
1088         FAM.getResult<PreservedCFGCheckerAnalysis>(*const_cast<Function *>(F));
1089       });
1090 
1091   PIC.registerAfterPassInvalidatedCallback(
1092       [this](StringRef P, const PreservedAnalyses &PassPA) {
1093 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1094         assert(PassStack.pop_back_val() == P &&
1095                "Before and After callbacks must correspond");
1096 #endif
1097         (void)this;
1098       });
1099 
1100   PIC.registerAfterPassCallback([this, &FAM,
1101                                  checkCFG](StringRef P, Any IR,
1102                                            const PreservedAnalyses &PassPA) {
1103 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1104     assert(PassStack.pop_back_val() == P &&
1105            "Before and After callbacks must correspond");
1106 #endif
1107     (void)this;
1108 
1109     if (!any_isa<const Function *>(IR))
1110       return;
1111 
1112     if (!PassPA.allAnalysesInSetPreserved<CFGAnalyses>() &&
1113         !PassPA.allAnalysesInSetPreserved<AllAnalysesOn<Function>>())
1114       return;
1115 
1116     const auto *F = any_cast<const Function *>(IR);
1117     if (auto *GraphBefore = FAM.getCachedResult<PreservedCFGCheckerAnalysis>(
1118             *const_cast<Function *>(F)))
1119       checkCFG(P, F->getName(), *GraphBefore,
1120                CFG(F, /* TrackBBLifetime */ false));
1121   });
1122 }
1123 
registerCallbacks(PassInstrumentationCallbacks & PIC)1124 void VerifyInstrumentation::registerCallbacks(
1125     PassInstrumentationCallbacks &PIC) {
1126   PIC.registerAfterPassCallback(
1127       [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1128         if (isIgnored(P) || P == "VerifierPass")
1129           return;
1130         if (any_isa<const Function *>(IR) || any_isa<const Loop *>(IR)) {
1131           const Function *F;
1132           if (any_isa<const Loop *>(IR))
1133             F = any_cast<const Loop *>(IR)->getHeader()->getParent();
1134           else
1135             F = any_cast<const Function *>(IR);
1136           if (DebugLogging)
1137             dbgs() << "Verifying function " << F->getName() << "\n";
1138 
1139           if (verifyFunction(*F))
1140             report_fatal_error("Broken function found, compilation aborted!");
1141         } else if (any_isa<const Module *>(IR) ||
1142                    any_isa<const LazyCallGraph::SCC *>(IR)) {
1143           const Module *M;
1144           if (any_isa<const LazyCallGraph::SCC *>(IR))
1145             M = any_cast<const LazyCallGraph::SCC *>(IR)
1146                     ->begin()
1147                     ->getFunction()
1148                     .getParent();
1149           else
1150             M = any_cast<const Module *>(IR);
1151           if (DebugLogging)
1152             dbgs() << "Verifying module " << M->getName() << "\n";
1153 
1154           if (verifyModule(*M))
1155             report_fatal_error("Broken module found, compilation aborted!");
1156         }
1157       });
1158 }
1159 
~InLineChangePrinter()1160 InLineChangePrinter::~InLineChangePrinter() {}
1161 
generateIRRepresentation(Any IR,StringRef PassID,ChangedIRData & D)1162 void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID,
1163                                                    ChangedIRData &D) {
1164   ChangedIRComparer::analyzeIR(IR, D);
1165 }
1166 
handleAfter(StringRef PassID,std::string & Name,const ChangedIRData & Before,const ChangedIRData & After,Any IR)1167 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
1168                                       const ChangedIRData &Before,
1169                                       const ChangedIRData &After, Any IR) {
1170   SmallString<20> Banner =
1171       formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1172   Out << Banner;
1173   ChangedIRComparer(Out, Before, After, UseColour)
1174       .compare(IR, "", PassID, Name);
1175   Out << "\n";
1176 }
1177 
same(const ChangedIRData & D1,const ChangedIRData & D2)1178 bool InLineChangePrinter::same(const ChangedIRData &D1,
1179                                const ChangedIRData &D2) {
1180   return D1 == D2;
1181 }
1182 
handleFunctionCompare(StringRef Name,StringRef Prefix,StringRef PassID,bool InModule,const ChangedFuncData & Before,const ChangedFuncData & After)1183 void ChangedIRComparer::handleFunctionCompare(StringRef Name, StringRef Prefix,
1184                                               StringRef PassID, bool InModule,
1185                                               const ChangedFuncData &Before,
1186                                               const ChangedFuncData &After) {
1187   // Print a banner when this is being shown in the context of a module
1188   if (InModule)
1189     Out << "\n*** IR for function " << Name << " ***\n";
1190 
1191   ChangedFuncData::report(
1192       Before, After, [&](const ChangedBlockData *B, const ChangedBlockData *A) {
1193         StringRef BStr = B ? B->getBody() : "\n";
1194         StringRef AStr = A ? A->getBody() : "\n";
1195         const std::string Removed =
1196             UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1197         const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1198         const std::string NoChange = " %l\n";
1199         Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1200       });
1201 }
1202 
registerCallbacks(PassInstrumentationCallbacks & PIC)1203 void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
1204   if (PrintChanged == ChangePrinter::PrintChangedDiffVerbose ||
1205       PrintChanged == ChangePrinter::PrintChangedDiffQuiet ||
1206       PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose ||
1207       PrintChanged == ChangePrinter::PrintChangedColourDiffQuiet)
1208     TextChangeReporter<ChangedIRData>::registerRequiredCallbacks(PIC);
1209 }
1210 
StandardInstrumentations(bool DebugLogging,bool VerifyEach,PrintPassOptions PrintPassOpts)1211 StandardInstrumentations::StandardInstrumentations(
1212     bool DebugLogging, bool VerifyEach, PrintPassOptions PrintPassOpts)
1213     : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
1214       PrintChangedIR(PrintChanged == ChangePrinter::PrintChangedVerbose),
1215       PrintChangedDiff(
1216           PrintChanged == ChangePrinter::PrintChangedDiffVerbose ||
1217               PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose,
1218           PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose ||
1219               PrintChanged == ChangePrinter::PrintChangedColourDiffQuiet),
1220       Verify(DebugLogging), VerifyEach(VerifyEach) {}
1221 
registerCallbacks(PassInstrumentationCallbacks & PIC,FunctionAnalysisManager * FAM)1222 void StandardInstrumentations::registerCallbacks(
1223     PassInstrumentationCallbacks &PIC, FunctionAnalysisManager *FAM) {
1224   PrintIR.registerCallbacks(PIC);
1225   PrintPass.registerCallbacks(PIC);
1226   TimePasses.registerCallbacks(PIC);
1227   OptNone.registerCallbacks(PIC);
1228   OptBisect.registerCallbacks(PIC);
1229   if (FAM)
1230     PreservedCFGChecker.registerCallbacks(PIC, *FAM);
1231   PrintChangedIR.registerCallbacks(PIC);
1232   PseudoProbeVerification.registerCallbacks(PIC);
1233   if (VerifyEach)
1234     Verify.registerCallbacks(PIC);
1235   PrintChangedDiff.registerCallbacks(PIC);
1236 }
1237 
1238 namespace llvm {
1239 
1240 template class ChangeReporter<std::string>;
1241 template class TextChangeReporter<std::string>;
1242 
1243 template class ChangeReporter<ChangedIRData>;
1244 template class TextChangeReporter<ChangedIRData>;
1245 
1246 } // namespace llvm
1247