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";
75 out <<
": @" << symbolName.getValue();
78 out <<
" //----- //\n";
82void IRPrinterInstrumentation::runBeforePass(
Pass *pass,
Operation *op) {
83 if (isa<OpToOpPassAdaptor>(pass))
86 if (config->shouldPrintAfterOnlyOnChange())
87 beforePassFingerPrints.try_emplace(pass, op);
89 config->printBeforeIfEnabled(pass, op, [&](raw_ostream &out) {
90 printIRHeader(out,
"Before", pass, op, config->shouldPrintAtModuleScope());
91 printIR(op, config->shouldPrintAtModuleScope(), out,
92 config->getOpPrintingFlags());
97void IRPrinterInstrumentation::runAfterPass(Pass *pass, Operation *op) {
98 if (isa<OpToOpPassAdaptor>(pass))
102 if (config->shouldPrintAfterOnlyOnFailure())
107 if (config->shouldPrintAfterOnlyOnChange()) {
108 auto fingerPrintIt = beforePassFingerPrints.find(pass);
109 assert(fingerPrintIt != beforePassFingerPrints.end() &&
110 "expected valid fingerprint");
112 if (fingerPrintIt->second == OperationFingerPrint(op)) {
113 beforePassFingerPrints.erase(fingerPrintIt);
116 beforePassFingerPrints.erase(fingerPrintIt);
119 config->printAfterIfEnabled(pass, op, [&](raw_ostream &out) {
120 printIRHeader(out,
"After", pass, op, config->shouldPrintAtModuleScope());
121 printIR(op, config->shouldPrintAtModuleScope(), out,
122 config->getOpPrintingFlags());
127void IRPrinterInstrumentation::runAfterPassFailed(Pass *pass, Operation *op) {
128 if (isa<OpToOpPassAdaptor>(pass))
130 if (config->shouldPrintAfterOnlyOnChange())
131 beforePassFingerPrints.erase(pass);
133 config->printAfterIfEnabled(pass, op, [&](raw_ostream &out) {
134 printIRHeader(out,
"After", pass, op, config->shouldPrintAtModuleScope(),
136 printIR(op, config->shouldPrintAtModuleScope(), out,
137 config->getOpPrintingFlags());
148 bool printAfterOnlyOnChange,
149 bool printAfterOnlyOnFailure,
151 : printModuleScope(printModuleScope),
152 printAfterOnlyOnChange(printAfterOnlyOnChange),
153 printAfterOnlyOnFailure(printAfterOnlyOnFailure),
154 opPrintingFlags(opPrintingFlags) {}
182 BasicIRPrinterConfig(
183 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
184 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
185 bool printModuleScope,
bool printAfterOnlyOnChange,
189 printAfterOnlyOnFailure, opPrintingFlags),
190 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
191 shouldPrintAfterPass(std::move(shouldPrintAfterPass)), out(out) {
192 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
193 "expected at least one valid filter function");
197 PrintCallbackFn printCallback)
final {
198 if (shouldPrintBeforePass && shouldPrintBeforePass(pass, operation))
203 PrintCallbackFn printCallback)
final {
204 if (shouldPrintAfterPass && shouldPrintAfterPass(pass, operation))
209 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass;
210 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass;
223static std::pair<SmallVector<std::pair<std::string, std::string>>, std::string>
230 ++counters.try_emplace(op, -1).first->second;
232 countPrefix.push_back(counters[iter]);
233 StringAttr symbolNameAttr =
235 std::string symbolName =
236 symbolNameAttr ? symbolNameAttr.str() :
"no-symbol-name";
237 llvm::replace(symbolName,
'/',
'_');
238 llvm::replace(symbolName,
'\\',
'_');
241 llvm::join(llvm::split(iter->getName().getStringRef().str(),
'.'),
"_");
242 pathElements.emplace_back(std::move(opName), std::move(symbolName));
243 iter = iter->getParentOp();
246 std::reverse(countPrefix.begin(), countPrefix.end());
247 std::reverse(pathElements.begin(), pathElements.end());
249 std::string passFileName = llvm::formatv(
251 llvm::make_range(countPrefix.begin(), countPrefix.end()), passName);
253 return {pathElements, passFileName};
257 if (std::error_code ec =
258 llvm::sys::fs::create_directory(dirPath,
true)) {
259 llvm::errs() <<
"Error while creating directory " << dirPath <<
": "
260 << ec.message() <<
"\n";
268static std::unique_ptr<llvm::ToolOutputFile>
270 llvm::StringRef rootDir,
276 auto [opAndSymbolNames, fileName] =
285 for (
const auto &[opName, symbolName] : opAndSymbolNames) {
286 llvm::sys::path::append(path, opName +
"_" + symbolName);
292 llvm::sys::path::append(path, fileName);
294 std::unique_ptr<llvm::ToolOutputFile> file =
openOutputFile(path, &error);
296 llvm::errs() <<
"Error opening output file " << path <<
": " << error
307struct FileTreeIRPrinterConfig :
public PassManager::IRPrinterConfig {
308 FileTreeIRPrinterConfig(
309 std::function<
bool(Pass *, Operation *)> shouldPrintBeforePass,
310 std::function<
bool(Pass *, Operation *)> shouldPrintAfterPass,
311 bool printModuleScope,
bool printAfterOnlyOnChange,
312 bool printAfterOnlyOnFailure, OpPrintingFlags opPrintingFlags,
313 llvm::StringRef treeDir)
314 : IRPrinterConfig(printModuleScope, printAfterOnlyOnChange,
315 printAfterOnlyOnFailure, opPrintingFlags),
316 shouldPrintBeforePass(std::move(shouldPrintBeforePass)),
317 shouldPrintAfterPass(std::move(shouldPrintAfterPass)),
319 assert((this->shouldPrintBeforePass || this->shouldPrintAfterPass) &&
320 "expected at least one valid filter function");
323 void printBeforeIfEnabled(Pass *pass, Operation *operation,
324 PrintCallbackFn printCallback)
final {
325 if (!shouldPrintBeforePass || !shouldPrintBeforePass(pass, operation))
328 operation, pass->
getArgument(), treeDir, counters);
331 printCallback(file->os());
335 void printAfterIfEnabled(Pass *pass, Operation *operation,
336 PrintCallbackFn printCallback)
final {
337 if (!shouldPrintAfterPass || !shouldPrintAfterPass(pass, operation))
340 operation, pass->
getArgument(), treeDir, counters);
343 printCallback(file->os());
348 std::function<bool(Pass *, Operation *)> shouldPrintBeforePass;
349 std::function<bool(Pass *, Operation *)> shouldPrintAfterPass;
356 llvm::DenseMap<Operation *, unsigned> counters;
364 if (config->shouldPrintAtModuleScope() &&
366 llvm::report_fatal_error(
"IR printing can't be setup on a pass-manager "
367 "without disabling multi-threading first.");
369 std::make_unique<IRPrinterInstrumentation>(std::move(config)));
374 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
375 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
376 bool printModuleScope,
bool printAfterOnlyOnChange,
380 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
381 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
382 opPrintingFlags, out));
387 std::function<
bool(
Pass *,
Operation *)> shouldPrintBeforePass,
388 std::function<
bool(
Pass *,
Operation *)> shouldPrintAfterPass,
389 bool printModuleScope,
bool printAfterOnlyOnChange,
390 bool printAfterOnlyOnFailure, StringRef printTreeDir,
393 std::move(shouldPrintBeforePass), std::move(shouldPrintAfterPass),
394 printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
395 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.
AttrClass getAttrOfType(StringAttr name)
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.
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.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap