Skip to content

Commit 11827f0

Browse files
committed
Add -mlir-reproducer-before-all
1 parent 72cbeca commit 11827f0

File tree

8 files changed

+126
-0
lines changed

8 files changed

+126
-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: 70 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,67 @@ struct FileTreeIRPrinterConfig : public PassManager::IRPrinterConfig {
345346
llvm::DenseMap<Operation *, unsigned> counters;
346347
};
347348

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

350412
/// Add an instrumentation to print the IR before and after pass execution,
@@ -383,3 +445,11 @@ void PassManager::enableIRPrintingToFileTree(
383445
printModuleScope, printAfterOnlyOnChange, printAfterOnlyOnFailure,
384446
opPrintingFlags, printTreeDir));
385447
}
448+
449+
/// Add an instrumentation to print the IR before and after pass execution.
450+
void PassManager::enableReproducerBeforeAll(StringRef outputDir) {
451+
if (getContext()->isMultithreadingEnabled())
452+
llvm::report_fatal_error("IR printing can't be setup on a pass-manager "
453+
"without disabling multi-threading first.");
454+
addInstrumentation(std::make_unique<ReproducerBeforeAll>(outputDir));
455+
}

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)