13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/FormatVariadic.h"
16 #include "llvm/Support/Path.h"
17 #include "llvm/Support/ToolOutputFile.h"
29 IRPrinterInstrumentation(std::unique_ptr<PassManager::IRPrinterConfig> config)
30 : config(std::move(config)) {}
39 std::unique_ptr<PassManager::IRPrinterConfig> config;
51 if (!printModuleScope)
52 return op->
print(out <<
" //----- //\n",
56 out <<
" ('" << op->
getName() <<
"' operation";
59 out <<
": @" << symbolName.getValue();
60 out <<
") //----- //\n";
63 auto *topLevelOp = op;
64 while (
auto *parentOp = topLevelOp->getParentOp())
65 topLevelOp = parentOp;
66 topLevelOp->
print(out, flags);
70 void IRPrinterInstrumentation::runBeforePass(
Pass *pass,
Operation *op) {
71 if (isa<OpToOpPassAdaptor>(pass))
74 if (config->shouldPrintAfterOnlyOnChange())
75 beforePassFingerPrints.try_emplace(pass, op);
77 config->printBeforeIfEnabled(pass, op, [&](raw_ostream &out) {
78 out <<
"// -----// IR Dump Before " << pass->
getName() <<
" ("
80 printIR(op, config->shouldPrintAtModuleScope(), out,
81 config->getOpPrintingFlags());
86 void IRPrinterInstrumentation::runAfterPass(
Pass *pass,
Operation *op) {
87 if (isa<OpToOpPassAdaptor>(pass))
91 if (config->shouldPrintAfterOnlyOnFailure())
96 if (config->shouldPrintAfterOnlyOnChange()) {
97 auto fingerPrintIt = beforePassFingerPrints.find(pass);
98 assert(fingerPrintIt != beforePassFingerPrints.end() &&
99 "expected valid fingerprint");
102 beforePassFingerPrints.erase(fingerPrintIt);
105 beforePassFingerPrints.erase(fingerPrintIt);
108 config->printAfterIfEnabled(pass, op, [&](raw_ostream &out) {
109 out <<
"// -----// IR Dump After " << pass->
getName() <<
" ("
111 printIR(op, config->shouldPrintAtModuleScope(), out,
112 config->getOpPrintingFlags());
117 void IRPrinterInstrumentation::runAfterPassFailed(
Pass *pass,
Operation *op) {
118 if (isa<OpToOpPassAdaptor>(pass))
120 if (config->shouldPrintAfterOnlyOnChange())
121 beforePassFingerPrints.erase(pass);
123 config->printAfterIfEnabled(pass, op, [&](raw_ostream &out) {
124 out << formatv(
"// -----// IR Dump After {0} Failed ({1})", pass->
getName(),
126 printIR(op, config->shouldPrintAtModuleScope(), out,
127 config->getOpPrintingFlags());
138 bool printAfterOnlyOnChange,
139 bool printAfterOnlyOnFailure,
141 : printModuleScope(printModuleScope),
142 printAfterOnlyOnChange(printAfterOnlyOnChange),
143 printAfterOnlyOnFailure(printAfterOnlyOnFailure),
144 opPrintingFlags(opPrintingFlags) {}
172 BasicIRPrinterConfig(
173 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
174 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
175 bool printModuleScope,
bool printAfterOnlyOnChange,
179 printAfterOnlyOnFailure, opPrintingFlags),
180 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
181 shouldPrintAfterPass(std::move(shouldPrintAfterPass)), out(out) {
182 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
183 "expected at least one valid filter function");
187 PrintCallbackFn printCallback)
final {
188 if (shouldPrintBeforePass && shouldPrintBeforePass(pass, operation))
193 PrintCallbackFn printCallback)
final {
194 if (shouldPrintAfterPass && shouldPrintAfterPass(pass, operation))
199 std::function<bool(
Pass *,
Operation *)> shouldPrintBeforePass;
200 std::function<bool(
Pass *,
Operation *)> shouldPrintAfterPass;
213 static std::pair<SmallVector<std::pair<std::string, StringRef>>, std::string>
219 if (!counters.contains(op))
225 countPrefix.push_back(counters[iter]);
226 StringAttr symbolName =
229 llvm::join(llvm::split(iter->getName().getStringRef().str(),
'.'),
"_");
230 pathElements.emplace_back(opName, symbolName ? symbolName.strref()
232 iter = iter->getParentOp();
235 std::reverse(countPrefix.begin(), countPrefix.end());
236 std::reverse(pathElements.begin(), pathElements.end());
238 std::string passFileName = llvm::formatv(
240 llvm::make_range(countPrefix.begin(), countPrefix.end()), passName);
242 return {pathElements, passFileName};
246 if (std::error_code ec =
247 llvm::sys::fs::create_directory(dirPath,
true)) {
248 llvm::errs() <<
"Error while creating directory " << dirPath <<
": "
249 << ec.message() <<
"\n";
257 static std::unique_ptr<llvm::ToolOutputFile>
259 llvm::StringRef rootDir,
265 auto [opAndSymbolNames, fileName] =
274 for (
const auto &[opName, symbolName] : opAndSymbolNames) {
275 llvm::sys::path::append(path, opName +
"_" + symbolName);
281 llvm::sys::path::append(path, fileName);
283 std::unique_ptr<llvm::ToolOutputFile> file =
openOutputFile(path, &error);
285 llvm::errs() <<
"Error opening output file " << path <<
": " << error
297 FileTreeIRPrinterConfig(
298 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
299 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
300 bool printModuleScope,
bool printAfterOnlyOnChange,
302 llvm::StringRef treeDir)
303 : IRPrinterConfig(printModuleScope, printAfterOnlyOnChange,
304 printAfterOnlyOnFailure, opPrintingFlags),
305 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
306 shouldPrintAfterPass(std::move(shouldPrintAfterPass)),
308 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
309 "expected at least one valid filter function");
313 PrintCallbackFn printCallback)
final {
314 if (!shouldPrintBeforePass || !shouldPrintBeforePass(pass, operation))
317 operation, pass->
getArgument(), treeDir, counters);
320 printCallback(file->os());
325 PrintCallbackFn printCallback)
final {
326 if (!shouldPrintAfterPass || !shouldPrintAfterPass(pass, operation))
329 operation, pass->
getArgument(), treeDir, counters);
332 printCallback(file->os());
337 std::function<bool(
Pass *,
Operation *)> shouldPrintBeforePass;
338 std::function<bool(
Pass *,
Operation *)> shouldPrintAfterPass;
353 if (config->shouldPrintAtModuleScope() &&
355 llvm::report_fatal_error(
"IR printing can't be setup on a pass-manager "
356 "without disabling multi-threading first.");
358 std::make_unique<IRPrinterInstrumentation>(std::move(config)));
363 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
364 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
365 bool printModuleScope,
bool printAfterOnlyOnChange,
366 bool printAfterOnlyOnFailure, raw_ostream &out,
369 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
370 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
371 opPrintingFlags, out));
376 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
377 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
378 bool printModuleScope,
bool printAfterOnlyOnChange,
379 bool printAfterOnlyOnFailure, StringRef printTreeDir,
382 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
383 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
384 opPrintingFlags, printTreeDir));
static std::pair< SmallVector< std::pair< std::string, StringRef > >, std::string > getOpAndSymbolNames(Operation *op, StringRef passName, llvm::DenseMap< Operation *, unsigned > &counters)
Return pairs of (sanitized op name, symbol name) for op and all parent operations.
static std::unique_ptr< llvm::ToolOutputFile > createTreePrinterOutputPath(Operation *op, llvm::StringRef passArgument, llvm::StringRef rootDir, llvm::DenseMap< Operation *, unsigned > &counters)
Creates directories (if required) and opens an output file for the FileTreeIRPrinterConfig.
static void printIR(Operation *op, bool printModuleScope, raw_ostream &out, OpPrintingFlags flags)
static LogicalResult createDirectoryOrPrintErr(llvm::StringRef dirPath)
Set of flags used to control the behavior of the various IR print methods (e.g.
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
A unique fingerprint for a specific operation, and all of it's internal operations (if includeNested ...
Operation is the basic unit of execution within MLIR.
AttrClass getAttrOfType(StringAttr name)
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
Block * getBlock()
Returns the operation block that contains this operation.
OperationName getName()
The name of an operation is the key identifier for it.
PassInstrumentation provides several entry points into the pass manager infrastructure.
A configuration struct provided to the IR printer instrumentation.
virtual ~IRPrinterConfig()
IRPrinterConfig(bool printModuleScope=false, bool printAfterOnlyOnChange=false, bool printAfterOnlyOnFailure=false, OpPrintingFlags opPrintingFlags=OpPrintingFlags())
Initialize the configuration.
virtual void printBeforeIfEnabled(Pass *pass, Operation *operation, PrintCallbackFn printCallback)
A hook that may be overridden by a derived config that checks if the IR of 'operation' should be dump...
virtual void printAfterIfEnabled(Pass *pass, Operation *operation, PrintCallbackFn printCallback)
A hook that may be overridden by a derived config that checks if the IR of 'operation' should be dump...
MLIRContext * getContext() const
Return an instance of the context.
void enableIRPrinting(std::unique_ptr< IRPrinterConfig > config)
Add an instrumentation to print the IR before and after pass execution, using the provided configurat...
void enableIRPrintingToFileTree(std::function< bool(Pass *, Operation *)> shouldPrintBeforePass=[](Pass *, Operation *) { return true;}, std::function< bool(Pass *, Operation *)> shouldPrintAfterPass=[](Pass *, Operation *) { return true;}, bool printModuleScope=true, bool printAfterOnlyOnChange=true, bool printAfterOnlyOnFailure=false, llvm::StringRef printTreeDir=".pass_manager_output", OpPrintingFlags opPrintingFlags=OpPrintingFlags())
Similar to enableIRPrinting above, except that instead of printing the IR to a single output stream,...
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
The abstract base pass class.
virtual StringRef getName() const =0
Returns the derived pass name.
virtual StringRef getArgument() const
Return the command line argument used when registering this pass.
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Include the generated interface declarations.
std::unique_ptr< llvm::ToolOutputFile > openOutputFile(llvm::StringRef outputFilename, std::string *errorMessage=nullptr)
Open the file specified by its name for writing.