13#include "llvm/ADT/STLExtras.h"
14#include "llvm/ADT/StringExtras.h"
15#include "llvm/Support/FileSystem.h"
16#include "llvm/Support/FormatVariadic.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/ToolOutputFile.h"
30 IRPrinterInstrumentation(std::unique_ptr<PassManager::IRPrinterConfig> config)
31 : config(std::move(config)) {}
35 void runBeforePass(Pass *pass, Operation *op)
override;
36 void runAfterPass(Pass *pass, Operation *op)
override;
37 void runAfterPassFailed(Pass *pass, Operation *op)
override;
40 std::unique_ptr<PassManager::IRPrinterConfig> config;
52 if (!printModuleScope)
57 auto *topLevelOp = op;
58 while (
auto *parentOp = topLevelOp->getParentOp())
59 topLevelOp = parentOp;
60 topLevelOp->
print(out, flags);
65 bool failed =
false) {
66 out <<
"// -----// IR Dump " << title <<
" " << pass->
getName();
71 if (printModuleScope) {
72 out <<
" ('" << op->
getName() <<
"' operation";
73 if (
auto symbol = dyn_cast<SymbolOpInterface>(op))
74 out <<
": @" << symbol.getName();
77 out <<
" //----- //\n";
81void IRPrinterInstrumentation::runBeforePass(
Pass *pass,
Operation *op) {
82 if (isa<OpToOpPassAdaptor>(pass))
85 if (config->shouldPrintAfterOnlyOnChange())
86 beforePassFingerPrints.try_emplace(pass, op);
88 config->printBeforeIfEnabled(pass, op, [&](raw_ostream &out) {
89 printIRHeader(out,
"Before", pass, op, config->shouldPrintAtModuleScope());
90 printIR(op, config->shouldPrintAtModuleScope(), out,
91 config->getOpPrintingFlags());
96void IRPrinterInstrumentation::runAfterPass(Pass *pass, Operation *op) {
97 if (isa<OpToOpPassAdaptor>(pass))
101 if (config->shouldPrintAfterOnlyOnFailure())
106 if (config->shouldPrintAfterOnlyOnChange()) {
107 auto fingerPrintIt = beforePassFingerPrints.find(pass);
108 assert(fingerPrintIt != beforePassFingerPrints.end() &&
109 "expected valid fingerprint");
111 if (fingerPrintIt->second == OperationFingerPrint(op)) {
112 beforePassFingerPrints.erase(fingerPrintIt);
115 beforePassFingerPrints.erase(fingerPrintIt);
118 config->printAfterIfEnabled(pass, op, [&](raw_ostream &out) {
119 printIRHeader(out,
"After", pass, op, config->shouldPrintAtModuleScope());
120 printIR(op, config->shouldPrintAtModuleScope(), out,
121 config->getOpPrintingFlags());
126void IRPrinterInstrumentation::runAfterPassFailed(Pass *pass, Operation *op) {
127 if (isa<OpToOpPassAdaptor>(pass))
129 if (config->shouldPrintAfterOnlyOnChange())
130 beforePassFingerPrints.erase(pass);
132 config->printAfterIfEnabled(pass, op, [&](raw_ostream &out) {
133 printIRHeader(out,
"After", pass, op, config->shouldPrintAtModuleScope(),
135 printIR(op, config->shouldPrintAtModuleScope(), out,
136 config->getOpPrintingFlags());
147 bool printAfterOnlyOnChange,
148 bool printAfterOnlyOnFailure,
150 : printModuleScope(printModuleScope),
151 printAfterOnlyOnChange(printAfterOnlyOnChange),
152 printAfterOnlyOnFailure(printAfterOnlyOnFailure),
153 opPrintingFlags(opPrintingFlags) {}
181 BasicIRPrinterConfig(
182 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
183 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
184 bool printModuleScope,
bool printAfterOnlyOnChange,
188 printAfterOnlyOnFailure, opPrintingFlags),
189 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
190 shouldPrintAfterPass(std::move(shouldPrintAfterPass)), out(out) {
191 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
192 "expected at least one valid filter function");
196 PrintCallbackFn printCallback)
final {
197 if (shouldPrintBeforePass && shouldPrintBeforePass(pass, operation))
202 PrintCallbackFn printCallback)
final {
203 if (shouldPrintAfterPass && shouldPrintAfterPass(pass, operation))
208 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass;
209 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass;
222static std::pair<SmallVector<std::pair<std::string, std::string>>, std::string>
229 ++counters.try_emplace(op, -1).first->second;
231 countPrefix.push_back(counters[iter]);
232 auto symbol = dyn_cast<SymbolOpInterface>(iter);
233 std::string symbolName = symbol ? symbol.getName().str() :
"no-symbol-name";
234 llvm::replace(symbolName,
'/',
'_');
235 llvm::replace(symbolName,
'\\',
'_');
238 llvm::join(llvm::split(iter->getName().getStringRef().str(),
'.'),
"_");
239 pathElements.emplace_back(std::move(opName), std::move(symbolName));
240 iter = iter->getParentOp();
243 std::reverse(countPrefix.begin(), countPrefix.end());
244 std::reverse(pathElements.begin(), pathElements.end());
246 std::string passFileName = llvm::formatv(
248 llvm::make_range(countPrefix.begin(), countPrefix.end()), passName);
250 return {pathElements, passFileName};
254 if (std::error_code ec =
255 llvm::sys::fs::create_directory(dirPath,
true)) {
256 llvm::errs() <<
"Error while creating directory " << dirPath <<
": "
257 << ec.message() <<
"\n";
265static std::unique_ptr<llvm::ToolOutputFile>
267 llvm::StringRef rootDir,
273 auto [opAndSymbolNames, fileName] =
282 for (
const auto &[opName, symbolName] : opAndSymbolNames) {
283 llvm::sys::path::append(path, opName +
"_" + symbolName);
289 llvm::sys::path::append(path, fileName);
291 std::unique_ptr<llvm::ToolOutputFile> file =
openOutputFile(path, &error);
293 llvm::errs() <<
"Error opening output file " << path <<
": " << error
304struct FileTreeIRPrinterConfig :
public PassManager::IRPrinterConfig {
305 FileTreeIRPrinterConfig(
306 std::function<
bool(Pass *, Operation *)> shouldPrintBeforePass,
307 std::function<
bool(Pass *, Operation *)> shouldPrintAfterPass,
308 bool printModuleScope,
bool printAfterOnlyOnChange,
309 bool printAfterOnlyOnFailure, OpPrintingFlags opPrintingFlags,
310 llvm::StringRef treeDir)
311 : IRPrinterConfig(printModuleScope, printAfterOnlyOnChange,
312 printAfterOnlyOnFailure, opPrintingFlags),
313 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
314 shouldPrintAfterPass(std::move(shouldPrintAfterPass)),
316 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
317 "expected at least one valid filter function");
320 void printBeforeIfEnabled(Pass *pass, Operation *operation,
321 PrintCallbackFn printCallback)
final {
322 if (!shouldPrintBeforePass || !shouldPrintBeforePass(pass, operation))
325 operation, pass->
getArgument(), treeDir, counters);
328 printCallback(file->os());
332 void printAfterIfEnabled(Pass *pass, Operation *operation,
333 PrintCallbackFn printCallback)
final {
334 if (!shouldPrintAfterPass || !shouldPrintAfterPass(pass, operation))
337 operation, pass->
getArgument(), treeDir, counters);
340 printCallback(file->os());
345 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass;
346 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass;
353 llvm::DenseMap<Operation *, unsigned> counters;
361 if (config->shouldPrintAtModuleScope() &&
363 llvm::report_fatal_error(
"IR printing can't be setup on a pass-manager "
364 "without disabling multi-threading first.");
366 std::make_unique<IRPrinterInstrumentation>(std::move(config)));
371 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
372 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
373 bool printModuleScope,
bool printAfterOnlyOnChange,
377 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
378 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
379 opPrintingFlags, out));
384 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
385 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
386 bool printModuleScope,
bool printAfterOnlyOnChange,
387 bool printAfterOnlyOnFailure, StringRef printTreeDir,
390 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
391 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
392 opPrintingFlags, printTreeDir));
static std::pair< SmallVector< std::pair< std::string, std::string > >, 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 void printIR(Operation *op, bool printModuleScope, raw_ostream &out, OpPrintingFlags flags)
static void printIRHeader(raw_ostream &out, StringRef title, Pass *pass, Operation *op, bool printModuleScope, bool failed=false)
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 LogicalResult createDirectoryOrPrintErr(llvm::StringRef dirPath)
Set of flags used to control the behavior of the various IR print methods (e.g.
OpPrintingFlags & useLocalScope(bool enable=true)
Use local scope when printing the operation.
Operation is the basic unit of execution within MLIR.
Block * getBlock()
Returns the operation block that contains this operation.
OperationName getName()
The name of an operation is the key identifier for it.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
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.
function_ref< void(raw_ostream &)> PrintCallbackFn
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...
void enableIRPrinting(std::unique_ptr< IRPrinterConfig > config)
Add an instrumentation to print the IR before and after pass execution, using the provided configurat...
MLIRContext * getContext() const
Return an instance of the context.
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.
void printAsTextualPipeline(raw_ostream &os, bool pretty=false)
Prints out the pass in the textual representation of pipelines.
virtual StringRef getName() const =0
Returns the derived pass name.
virtual StringRef getArgument() const
Return the command line argument used when registering this pass.
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.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap