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/Analysis/CallGraphSCCPass.h"
19 #include "llvm/Analysis/LazyCallGraph.h"
20 #include "llvm/Analysis/LoopInfo.h"
21 #include "llvm/IR/Function.h"
22 #include "llvm/IR/IRPrintingPasses.h"
23 #include "llvm/IR/Module.h"
24 #include "llvm/IR/PassInstrumentation.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Support/Debug.h"
27 #include "llvm/Support/FormatVariadic.h"
28 #include "llvm/Support/raw_ostream.h"
29 
30 using namespace llvm;
31 
32 // TODO: remove once all required passes are marked as such.
33 static cl::opt<bool>
34     EnableOptnone("enable-npm-optnone", cl::init(false),
35                   cl::desc("Enable skipping optional passes optnone functions "
36                            "under new pass manager"));
37 
38 namespace {
39 
40 /// Extracting Module out of \p IR unit. Also fills a textual description
41 /// of \p IR for use in header when printing.
42 Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) {
43   if (any_isa<const Module *>(IR))
44     return std::make_pair(any_cast<const Module *>(IR), std::string());
45 
46   if (any_isa<const Function *>(IR)) {
47     const Function *F = any_cast<const Function *>(IR);
48     if (!llvm::isFunctionInPrintList(F->getName()))
49       return None;
50     const Module *M = F->getParent();
51     return std::make_pair(M, formatv(" (function: {0})", F->getName()).str());
52   }
53 
54   if (any_isa<const LazyCallGraph::SCC *>(IR)) {
55     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
56     for (const LazyCallGraph::Node &N : *C) {
57       const Function &F = N.getFunction();
58       if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
59         const Module *M = F.getParent();
60         return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str());
61       }
62     }
63     return None;
64   }
65 
66   if (any_isa<const Loop *>(IR)) {
67     const Loop *L = any_cast<const Loop *>(IR);
68     const Function *F = L->getHeader()->getParent();
69     if (!isFunctionInPrintList(F->getName()))
70       return None;
71     const Module *M = F->getParent();
72     std::string LoopName;
73     raw_string_ostream ss(LoopName);
74     L->getHeader()->printAsOperand(ss, false);
75     return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str());
76   }
77 
78   llvm_unreachable("Unknown IR unit");
79 }
80 
81 void printIR(const Function *F, StringRef Banner,
82              StringRef Extra = StringRef()) {
83   if (!llvm::isFunctionInPrintList(F->getName()))
84     return;
85   dbgs() << Banner << Extra << "\n" << static_cast<const Value &>(*F);
86 }
87 
88 void printIR(const Module *M, StringRef Banner, StringRef Extra = StringRef()) {
89   if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) {
90     dbgs() << Banner << Extra << "\n";
91     M->print(dbgs(), nullptr, false);
92   } else {
93     for (const auto &F : M->functions()) {
94       printIR(&F, Banner, Extra);
95     }
96   }
97 }
98 
99 void printIR(const LazyCallGraph::SCC *C, StringRef Banner,
100              StringRef Extra = StringRef()) {
101   bool BannerPrinted = false;
102   for (const LazyCallGraph::Node &N : *C) {
103     const Function &F = N.getFunction();
104     if (!F.isDeclaration() && llvm::isFunctionInPrintList(F.getName())) {
105       if (!BannerPrinted) {
106         dbgs() << Banner << Extra << "\n";
107         BannerPrinted = true;
108       }
109       F.print(dbgs());
110     }
111   }
112 }
113 void printIR(const Loop *L, StringRef Banner) {
114   const Function *F = L->getHeader()->getParent();
115   if (!llvm::isFunctionInPrintList(F->getName()))
116     return;
117   llvm::printLoop(const_cast<Loop &>(*L), dbgs(), std::string(Banner));
118 }
119 
120 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
121 /// llvm::Any and does actual print job.
122 void unwrapAndPrint(Any IR, StringRef Banner, bool ForceModule = false) {
123   if (ForceModule) {
124     if (auto UnwrappedModule = unwrapModule(IR))
125       printIR(UnwrappedModule->first, Banner, UnwrappedModule->second);
126     return;
127   }
128 
129   if (any_isa<const Module *>(IR)) {
130     const Module *M = any_cast<const Module *>(IR);
131     assert(M && "module should be valid for printing");
132     printIR(M, Banner);
133     return;
134   }
135 
136   if (any_isa<const Function *>(IR)) {
137     const Function *F = any_cast<const Function *>(IR);
138     assert(F && "function should be valid for printing");
139     printIR(F, Banner);
140     return;
141   }
142 
143   if (any_isa<const LazyCallGraph::SCC *>(IR)) {
144     const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
145     assert(C && "scc should be valid for printing");
146     std::string Extra = std::string(formatv(" (scc: {0})", C->getName()));
147     printIR(C, Banner, Extra);
148     return;
149   }
150 
151   if (any_isa<const Loop *>(IR)) {
152     const Loop *L = any_cast<const Loop *>(IR);
153     assert(L && "Loop should be valid for printing");
154     printIR(L, Banner);
155     return;
156   }
157   llvm_unreachable("Unknown wrapped IR type");
158 }
159 
160 } // namespace
161 
162 PrintIRInstrumentation::~PrintIRInstrumentation() {
163   assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
164 }
165 
166 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) {
167   assert(StoreModuleDesc);
168   const Module *M = nullptr;
169   std::string Extra;
170   if (auto UnwrappedModule = unwrapModule(IR))
171     std::tie(M, Extra) = UnwrappedModule.getValue();
172   ModuleDescStack.emplace_back(M, Extra, PassID);
173 }
174 
175 PrintIRInstrumentation::PrintModuleDesc
176 PrintIRInstrumentation::popModuleDesc(StringRef PassID) {
177   assert(!ModuleDescStack.empty() && "empty ModuleDescStack");
178   PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val();
179   assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack");
180   return ModuleDesc;
181 }
182 
183 bool PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
184   if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"))
185     return true;
186 
187   // Saving Module for AfterPassInvalidated operations.
188   // Note: here we rely on a fact that we do not change modules while
189   // traversing the pipeline, so the latest captured module is good
190   // for all print operations that has not happen yet.
191   if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID))
192     pushModuleDesc(PassID, IR);
193 
194   if (!llvm::shouldPrintBeforePass(PassID))
195     return true;
196 
197   SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID);
198   unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR());
199   return true;
200 }
201 
202 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
203   if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"))
204     return;
205 
206   if (!llvm::shouldPrintAfterPass(PassID))
207     return;
208 
209   if (StoreModuleDesc)
210     popModuleDesc(PassID);
211 
212   SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID);
213   unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR());
214 }
215 
216 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
217   if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID))
218     return;
219 
220   if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"))
221     return;
222 
223   const Module *M;
224   std::string Extra;
225   StringRef StoredPassID;
226   std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID);
227   // Additional filtering (e.g. -filter-print-func) can lead to module
228   // printing being skipped.
229   if (!M)
230     return;
231 
232   SmallString<20> Banner =
233       formatv("*** IR Dump After {0} *** invalidated: ", PassID);
234   printIR(M, Banner, Extra);
235 }
236 
237 void PrintIRInstrumentation::registerCallbacks(
238     PassInstrumentationCallbacks &PIC) {
239   // BeforePass callback is not just for printing, it also saves a Module
240   // for later use in AfterPassInvalidated.
241   StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass();
242   if (llvm::shouldPrintBeforePass() || StoreModuleDesc)
243     PIC.registerBeforePassCallback(
244         [this](StringRef P, Any IR) { return this->printBeforePass(P, IR); });
245 
246   if (llvm::shouldPrintAfterPass()) {
247     PIC.registerAfterPassCallback(
248         [this](StringRef P, Any IR) { this->printAfterPass(P, IR); });
249     PIC.registerAfterPassInvalidatedCallback(
250         [this](StringRef P) { this->printAfterPassInvalidated(P); });
251   }
252 }
253 
254 void OptNoneInstrumentation::registerCallbacks(
255     PassInstrumentationCallbacks &PIC) {
256   PIC.registerBeforePassCallback(
257       [this](StringRef P, Any IR) { return this->skip(P, IR); });
258 }
259 
260 bool OptNoneInstrumentation::skip(StringRef PassID, Any IR) {
261   if (!EnableOptnone)
262     return true;
263   const Function *F = nullptr;
264   if (any_isa<const Function *>(IR)) {
265     F = any_cast<const Function *>(IR);
266   } else if (any_isa<const Loop *>(IR)) {
267     F = any_cast<const Loop *>(IR)->getHeader()->getParent();
268   }
269   if (F && F->hasOptNone()) {
270     if (DebugLogging)
271       dbgs() << "Skipping pass: " << PassID << " (optnone)\n";
272     return false;
273   }
274   return true;
275 }
276 
277 void StandardInstrumentations::registerCallbacks(
278     PassInstrumentationCallbacks &PIC) {
279   PrintIR.registerCallbacks(PIC);
280   TimePasses.registerCallbacks(PIC);
281   OptNone.registerCallbacks(PIC);
282 }
283