1 //===- Standard pass instrumentations handling ----------------*- C++ -*--===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file defines IR-printing pass instrumentation callbacks as well as
11 /// StandardInstrumentations class that manages standard pass instrumentations.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/Passes/StandardInstrumentations.h"
16 #include "llvm/ADT/Optional.h"
17 #include "llvm/Analysis/CallGraphSCCPass.h"
18 #include "llvm/Analysis/LazyCallGraph.h"
19 #include "llvm/Analysis/LoopInfo.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/IRPrintingPasses.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/IR/PassInstrumentation.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/FormatVariadic.h"
26 #include "llvm/Support/raw_ostream.h"
32 /// Extracting Module out of \p IR unit. Also fills a textual description
33 /// of \p IR for use in header when printing.
34 Optional
<std::pair
<const Module
*, std::string
>> unwrapModule(Any IR
) {
35 if (any_isa
<const Module
*>(IR
))
36 return std::make_pair(any_cast
<const Module
*>(IR
), std::string());
38 if (any_isa
<const Function
*>(IR
)) {
39 const Function
*F
= any_cast
<const Function
*>(IR
);
40 if (!llvm::isFunctionInPrintList(F
->getName()))
42 const Module
*M
= F
->getParent();
43 return std::make_pair(M
, formatv(" (function: {0})", F
->getName()).str());
46 if (any_isa
<const LazyCallGraph::SCC
*>(IR
)) {
47 const LazyCallGraph::SCC
*C
= any_cast
<const LazyCallGraph::SCC
*>(IR
);
48 for (const LazyCallGraph::Node
&N
: *C
) {
49 const Function
&F
= N
.getFunction();
50 if (!F
.isDeclaration() && isFunctionInPrintList(F
.getName())) {
51 const Module
*M
= F
.getParent();
52 return std::make_pair(M
, formatv(" (scc: {0})", C
->getName()).str());
58 if (any_isa
<const Loop
*>(IR
)) {
59 const Loop
*L
= any_cast
<const Loop
*>(IR
);
60 const Function
*F
= L
->getHeader()->getParent();
61 if (!isFunctionInPrintList(F
->getName()))
63 const Module
*M
= F
->getParent();
65 raw_string_ostream
ss(LoopName
);
66 L
->getHeader()->printAsOperand(ss
, false);
67 return std::make_pair(M
, formatv(" (loop: {0})", ss
.str()).str());
70 llvm_unreachable("Unknown IR unit");
73 void printIR(const Module
*M
, StringRef Banner
, StringRef Extra
= StringRef()) {
74 dbgs() << Banner
<< Extra
<< "\n";
75 M
->print(dbgs(), nullptr, false);
77 void printIR(const Function
*F
, StringRef Banner
,
78 StringRef Extra
= StringRef()) {
79 if (!llvm::isFunctionInPrintList(F
->getName()))
81 dbgs() << Banner
<< Extra
<< "\n" << static_cast<const Value
&>(*F
);
83 void printIR(const LazyCallGraph::SCC
*C
, StringRef Banner
,
84 StringRef Extra
= StringRef()) {
85 bool BannerPrinted
= false;
86 for (const LazyCallGraph::Node
&N
: *C
) {
87 const Function
&F
= N
.getFunction();
88 if (!F
.isDeclaration() && llvm::isFunctionInPrintList(F
.getName())) {
90 dbgs() << Banner
<< Extra
<< "\n";
97 void printIR(const Loop
*L
, StringRef Banner
) {
98 const Function
*F
= L
->getHeader()->getParent();
99 if (!llvm::isFunctionInPrintList(F
->getName()))
101 llvm::printLoop(const_cast<Loop
&>(*L
), dbgs(), Banner
);
104 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
105 /// llvm::Any and does actual print job.
106 void unwrapAndPrint(Any IR
, StringRef Banner
, bool ForceModule
= false) {
108 if (auto UnwrappedModule
= unwrapModule(IR
))
109 printIR(UnwrappedModule
->first
, Banner
, UnwrappedModule
->second
);
113 if (any_isa
<const Module
*>(IR
)) {
114 const Module
*M
= any_cast
<const Module
*>(IR
);
115 assert(M
&& "module should be valid for printing");
120 if (any_isa
<const Function
*>(IR
)) {
121 const Function
*F
= any_cast
<const Function
*>(IR
);
122 assert(F
&& "function should be valid for printing");
127 if (any_isa
<const LazyCallGraph::SCC
*>(IR
)) {
128 const LazyCallGraph::SCC
*C
= any_cast
<const LazyCallGraph::SCC
*>(IR
);
129 assert(C
&& "scc should be valid for printing");
130 std::string Extra
= formatv(" (scc: {0})", C
->getName());
131 printIR(C
, Banner
, Extra
);
135 if (any_isa
<const Loop
*>(IR
)) {
136 const Loop
*L
= any_cast
<const Loop
*>(IR
);
137 assert(L
&& "Loop should be valid for printing");
141 llvm_unreachable("Unknown wrapped IR type");
146 PrintIRInstrumentation::~PrintIRInstrumentation() {
147 assert(ModuleDescStack
.empty() && "ModuleDescStack is not empty at exit");
150 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID
, Any IR
) {
151 assert(StoreModuleDesc
);
152 const Module
*M
= nullptr;
154 if (auto UnwrappedModule
= unwrapModule(IR
))
155 std::tie(M
, Extra
) = UnwrappedModule
.getValue();
156 ModuleDescStack
.emplace_back(M
, Extra
, PassID
);
159 PrintIRInstrumentation::PrintModuleDesc
160 PrintIRInstrumentation::popModuleDesc(StringRef PassID
) {
161 assert(!ModuleDescStack
.empty() && "empty ModuleDescStack");
162 PrintModuleDesc ModuleDesc
= ModuleDescStack
.pop_back_val();
163 assert(std::get
<2>(ModuleDesc
).equals(PassID
) && "malformed ModuleDescStack");
167 bool PrintIRInstrumentation::printBeforePass(StringRef PassID
, Any IR
) {
168 if (PassID
.startswith("PassManager<") || PassID
.contains("PassAdaptor<"))
171 // Saving Module for AfterPassInvalidated operations.
172 // Note: here we rely on a fact that we do not change modules while
173 // traversing the pipeline, so the latest captured module is good
174 // for all print operations that has not happen yet.
175 if (StoreModuleDesc
&& llvm::shouldPrintAfterPass(PassID
))
176 pushModuleDesc(PassID
, IR
);
178 if (!llvm::shouldPrintBeforePass(PassID
))
181 SmallString
<20> Banner
= formatv("*** IR Dump Before {0} ***", PassID
);
182 unwrapAndPrint(IR
, Banner
, llvm::forcePrintModuleIR());
186 void PrintIRInstrumentation::printAfterPass(StringRef PassID
, Any IR
) {
187 if (PassID
.startswith("PassManager<") || PassID
.contains("PassAdaptor<"))
190 if (!llvm::shouldPrintAfterPass(PassID
))
194 popModuleDesc(PassID
);
196 SmallString
<20> Banner
= formatv("*** IR Dump After {0} ***", PassID
);
197 unwrapAndPrint(IR
, Banner
, llvm::forcePrintModuleIR());
200 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID
) {
201 if (!StoreModuleDesc
|| !llvm::shouldPrintAfterPass(PassID
))
204 if (PassID
.startswith("PassManager<") || PassID
.contains("PassAdaptor<"))
209 StringRef StoredPassID
;
210 std::tie(M
, Extra
, StoredPassID
) = popModuleDesc(PassID
);
211 // Additional filtering (e.g. -filter-print-func) can lead to module
212 // printing being skipped.
216 SmallString
<20> Banner
=
217 formatv("*** IR Dump After {0} *** invalidated: ", PassID
);
218 printIR(M
, Banner
, Extra
);
221 void PrintIRInstrumentation::registerCallbacks(
222 PassInstrumentationCallbacks
&PIC
) {
223 // BeforePass callback is not just for printing, it also saves a Module
224 // for later use in AfterPassInvalidated.
225 StoreModuleDesc
= llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass();
226 if (llvm::shouldPrintBeforePass() || StoreModuleDesc
)
227 PIC
.registerBeforePassCallback(
228 [this](StringRef P
, Any IR
) { return this->printBeforePass(P
, IR
); });
230 if (llvm::shouldPrintAfterPass()) {
231 PIC
.registerAfterPassCallback(
232 [this](StringRef P
, Any IR
) { this->printAfterPass(P
, IR
); });
233 PIC
.registerAfterPassInvalidatedCallback(
234 [this](StringRef P
) { this->printAfterPassInvalidated(P
); });
238 void StandardInstrumentations::registerCallbacks(
239 PassInstrumentationCallbacks
&PIC
) {
240 PrintIR
.registerCallbacks(PIC
);
241 TimePasses
.registerCallbacks(PIC
);