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>
220 ++counters.try_emplace(op, -1).first->second;
222 countPrefix.push_back(counters[iter]);
223 StringAttr symbolName =
226 llvm::join(llvm::split(iter->getName().getStringRef().str(),
'.'),
"_");
227 pathElements.emplace_back(opName, symbolName ? symbolName.strref()
229 iter = iter->getParentOp();
232 std::reverse(countPrefix.begin(), countPrefix.end());
233 std::reverse(pathElements.begin(), pathElements.end());
235 std::string passFileName = llvm::formatv(
237 llvm::make_range(countPrefix.begin(), countPrefix.end()), passName);
239 return {pathElements, passFileName};
243 if (std::error_code ec =
244 llvm::sys::fs::create_directory(dirPath,
true)) {
245 llvm::errs() <<
"Error while creating directory " << dirPath <<
": "
246 << ec.message() <<
"\n";
254 static std::unique_ptr<llvm::ToolOutputFile>
256 llvm::StringRef rootDir,
262 auto [opAndSymbolNames, fileName] =
271 for (
const auto &[opName, symbolName] : opAndSymbolNames) {
272 llvm::sys::path::append(path, opName +
"_" + symbolName);
278 llvm::sys::path::append(path, fileName);
280 std::unique_ptr<llvm::ToolOutputFile> file =
openOutputFile(path, &error);
282 llvm::errs() <<
"Error opening output file " << path <<
": " << error
294 FileTreeIRPrinterConfig(
295 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
296 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
297 bool printModuleScope,
bool printAfterOnlyOnChange,
299 llvm::StringRef treeDir)
300 : IRPrinterConfig(printModuleScope, printAfterOnlyOnChange,
301 printAfterOnlyOnFailure, opPrintingFlags),
302 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
303 shouldPrintAfterPass(std::move(shouldPrintAfterPass)),
305 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
306 "expected at least one valid filter function");
310 PrintCallbackFn printCallback)
final {
311 if (!shouldPrintBeforePass || !shouldPrintBeforePass(pass, operation))
314 operation, pass->
getArgument(), treeDir, counters);
317 printCallback(file->os());
322 PrintCallbackFn printCallback)
final {
323 if (!shouldPrintAfterPass || !shouldPrintAfterPass(pass, operation))
326 operation, pass->
getArgument(), treeDir, counters);
329 printCallback(file->os());
334 std::function<bool(
Pass *,
Operation *)> shouldPrintBeforePass;
335 std::function<bool(
Pass *,
Operation *)> shouldPrintAfterPass;
350 if (config->shouldPrintAtModuleScope() &&
352 llvm::report_fatal_error(
"IR printing can't be setup on a pass-manager "
353 "without disabling multi-threading first.");
355 std::make_unique<IRPrinterInstrumentation>(std::move(config)));
360 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
361 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
362 bool printModuleScope,
bool printAfterOnlyOnChange,
363 bool printAfterOnlyOnFailure, raw_ostream &out,
366 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
367 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
368 opPrintingFlags, out));
373 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
374 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
375 bool printModuleScope,
bool printAfterOnlyOnChange,
376 bool printAfterOnlyOnFailure, StringRef printTreeDir,
379 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
380 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
381 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.