Skip to content

Commit 20a6720

Browse files
authored
Add -mlir-reproducer-before-all (#402)
* Add -mlir-reproducer-before-all
1 parent 7326995 commit 20a6720

File tree

8 files changed

+133
-0
lines changed

8 files changed

+133
-0
lines changed

mlir/include/mlir-c/Pass.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ mlirPassManagerRunOnOp(MlirPassManager passManager, MlirOperation op);
7878
MLIR_CAPI_EXPORTED void
7979
mlirPassManagerEnableIRPrinting(MlirPassManager passManager);
8080

81+
/// Enable lir-reproducer-before-all.
82+
MLIR_CAPI_EXPORTED void
83+
mlirPassManagerEnableReproducerBeforeAll(MlirPassManager passManager,
84+
MlirStringRef outputDir);
85+
8186
/// Enable / disable verify-each.
8287
MLIR_CAPI_EXPORTED void
8388
mlirPassManagerEnableVerifier(MlirPassManager passManager, bool enable);

mlir/include/mlir/Pass/PassManager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ class PassManager : public OpPassManager {
423423
llvm::StringRef printTreeDir = ".pass_manager_output",
424424
OpPrintingFlags opPrintingFlags = OpPrintingFlags());
425425

426+
/// Dump a reproducer before each pass into a file in the given output
427+
/// directory.
428+
void enableReproducerBeforeAll(llvm::StringRef outputDir);
429+
426430
//===--------------------------------------------------------------------===//
427431
// Pass Timing
428432

mlir/lib/Bindings/Python/Pass.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ void mlir::python::populatePassManagerSubmodule(py::module &m) {
7878
mlirPassManagerEnableIRPrinting(passManager.get());
7979
},
8080
"Enable mlir-print-ir-after-all.")
81+
.def(
82+
"enable_reproducer_before_all",
83+
[](PyPassManager &passManager, const std::string &outputDir) {
84+
mlirPassManagerEnableReproducerBeforeAll(
85+
passManager.get(),
86+
mlirStringRefCreate(outputDir.data(), outputDir.size()));
87+
},
88+
"Enable mlir-reproducer-before-all.")
8189
.def(
8290
"enable_verifier",
8391
[](PyPassManager &passManager, bool enable) {

mlir/lib/CAPI/IR/Pass.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ void mlirPassManagerEnableIRPrinting(MlirPassManager passManager) {
4848
return unwrap(passManager)->enableIRPrinting();
4949
}
5050

51+
void mlirPassManagerEnableReproducerBeforeAll(MlirPassManager passManager,
52+
MlirStringRef outputDir) {
53+
return unwrap(passManager)->enableReproducerBeforeAll(unwrap(outputDir));
54+
}
55+
5156
void mlirPassManagerEnableVerifier(MlirPassManager passManager, bool enable) {
5257
unwrap(passManager)->enableVerifier(enable);
5358
}

mlir/lib/Pass/IRPrinting.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "PassDetail.h"
10+
#include "mlir/IR/AsmState.h"
1011
#include "mlir/IR/SymbolTable.h"
1112
#include "mlir/Pass/PassManager.h"
1213
#include "mlir/Support/FileUtilities.h"
@@ -345,6 +346,74 @@ struct FileTreeIRPrinterConfig : public PassManager::IRPrinterConfig {
345346
llvm::DenseMap<Operation *, unsigned> counters;
346347
};
347348

349+
/// Print a pass pipeline like `builtin.module(func.func(cse))`
350+
/// from a list of scopes and the pass.
351+
template <typename RangeT>
352+
void printAsPassPipeline(RangeT scopes, Pass *pass, raw_ostream &os) {
353+
// Add pass scopes like 'builtin.module(emitc.tu('
354+
for (OperationName scope : scopes)
355+
os << scope << "(";
356+
pass->printAsTextualPipeline(os);
357+
for (OperationName _ : scopes)
358+
os << ")";
359+
}
360+
361+
/// A pass instrumentation to dump the IR before each pass into
362+
/// numbered files.
363+
/// It includes a mlir_reproducer info to rerun the pass.
364+
class ReproducerBeforeAll : public PassInstrumentation {
365+
public:
366+
ReproducerBeforeAll(mlir::StringRef outputDir) : outputDir(outputDir) {}
367+
void runBeforePass(Pass *pass, Operation *op) override;
368+
369+
std::string outputDir;
370+
371+
uint32_t counter = 0;
372+
};
373+
374+
void ReproducerBeforeAll::runBeforePass(Pass *pass, Operation *op) {
375+
// Skip adator passes (which adopt FuncOp passes to ModuleOp pass managers).
376+
if (isa<OpToOpPassAdaptor>(pass))
377+
return;
378+
379+
llvm::SmallString<128> path(outputDir);
380+
if (failed(createDirectoryOrPrintErr(path)))
381+
return;
382+
383+
// Open output file.
384+
std::string fileName =
385+
llvm::formatv("{0,0+2}_{1}.mlir", counter++, pass->getArgument());
386+
llvm::sys::path::append(path, fileName);
387+
388+
std::string error;
389+
std::unique_ptr<llvm::ToolOutputFile> file = openOutputFile(path, &error);
390+
if (!file) {
391+
llvm::errs() << "Error opening output file " << path << ": " << error
392+
<< "\n";
393+
return;
394+
}
395+
396+
SmallVector<OperationName> scopes;
397+
scopes.push_back(op->getName());
398+
while (Operation *parentOp = op->getParentOp()) {
399+
scopes.push_back(parentOp->getName());
400+
op = parentOp;
401+
}
402+
403+
std::string pipelineStr;
404+
llvm::raw_string_ostream passOS(pipelineStr);
405+
printAsPassPipeline(llvm::reverse(scopes), pass, passOS);
406+
407+
AsmState state(op);
408+
state.attachResourcePrinter("mlir_reproducer",
409+
[&](Operation *op, AsmResourceBuilder &builder) {
410+
builder.buildString("pipeline", pipelineStr);
411+
builder.buildBool("disable_threading", true);
412+
builder.buildBool("verify_each", true);
413+
});
414+
op->print(file->os(), state);
415+
file->keep();
416+
}
348417
} // namespace
349418

350419
/// Add an instrumentation to print the IR before and after pass execution,
@@ -383,3 +452,11 @@ void PassManager::enableIRPrintingToFileTree(
383452
printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
384453
opPrintingFlags, printTreeDir));
385454
}
455+
456+
/// Add an instrumentation to print the IR before and after pass execution.
457+
void PassManager::enableReproducerBeforeAll(StringRef outputDir) {
458+
if (getContext()->isMultithreadingEnabled())
459+
llvm::report_fatal_error("IR printing can't be setup on a pass-manager "
460+
"without disabling multi-threading first.");
461+
addInstrumentation(std::make_unique<ReproducerBeforeAll>(outputDir));
462+
}

mlir/lib/Pass/PassManagerOptions.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ struct PassManagerOptions {
6464
"tree rooted at this directory. Use in conjunction with "
6565
"mlir-print-ir-* flags")};
6666

67+
llvm::cl::opt<std::string> reproducerBeforeAllDir{
68+
"mlir-reproducer-before-all",
69+
llvm::cl::desc("Save a reproducer before each pass to this directory")};
70+
6771
/// Add an IR printing instrumentation if enabled by any 'print-ir' flags.
6872
void addPrinterInstrumentation(PassManager &pm);
6973

@@ -151,6 +155,9 @@ LogicalResult mlir::applyPassManagerCLOptions(PassManager &pm) {
151155
pm.enableCrashReproducerGeneration(options->reproducerFile,
152156
options->localReproducer);
153157

158+
if (!options->reproducerBeforeAllDir.empty())
159+
pm.enableReproducerBeforeAll(options->reproducerBeforeAllDir);
160+
154161
// Enable statistics dumping.
155162
if (options->passStatistics)
156163
pm.enableStatistics(options->passStatisticsDisplayMode);

mlir/python/mlir/_mlir_libs/_mlir/passmanager.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class PassManager:
1717
def _CAPICreate(self) -> object: ...
1818
def _testing_release(self) -> None: ...
1919
def enable_ir_printing(self) -> None: ...
20+
def enable_reproducer_before_all(self, output_dir: str) -> None: ...
2021
def enable_verifier(self, enable: bool) -> None: ...
2122
@staticmethod
2223
def parse(pipeline: str, context: Optional[_ir.Context] = None) -> PassManager: ...
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: rm -rf %t || true
2+
// RUN: mlir-opt %s -mlir-disable-threading -mlir-reproducer-before-all=%t \
3+
// RUN: -pass-pipeline='builtin.module(canonicalize,cse,func.func(canonicalize))'
4+
// RUN: FileCheck %s -input-file=%t/00_canonicalize.mlir --check-prefixes CHECK0
5+
// RUN: FileCheck %s -input-file=%t/01_cse.mlir --check-prefixes CHECK1
6+
// RUN: FileCheck %s -input-file=%t/02_canonicalize.mlir --check-prefixes CHECK2
7+
8+
builtin.module @outer {
9+
func.func @symA() {
10+
return
11+
}
12+
}
13+
14+
// CHECK0: module @outer {
15+
// CHECK0: {-#
16+
// CHECK0-NEXT: external_resources: {
17+
// CHECK0-NEXT: mlir_reproducer: {
18+
// CHECK0-NEXT: pipeline: "builtin.module(canonicalize
19+
// CHECK0-NEXT: disable_threading: true,
20+
// CHECK0-NEXT: verify_each: true
21+
// CHECK0-NEXT: }
22+
// CHECK0-NEXT: }
23+
// CHECK0-NEXT: #-}
24+
25+
// CHECK1: pipeline: "builtin.module(cse
26+
// CHECK2: pipeline: "builtin.module(func.func(canonicalize

0 commit comments

Comments
 (0)