[Mlir-commits] [mlir] [MLIR] Move the `mlir-generate-reproducer` option to be a PassManager option instead of mlir-opt (PR #159004)
    Mehdi Amini 
    llvmlistbot at llvm.org
       
    Thu Sep 25 04:19:29 PDT 2025
    
    
  
https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/159004
>From 67bb4b1ace986ffe26a6d5c9c58483103078da99 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Tue, 16 Sep 2025 04:14:54 -0700
Subject: [PATCH] [MLIR] Move the `mlir-generate-reproducer` option to be a
 PassManager option instead of mlir-opt
This makes it available to compilers in general, not limited to mlir-opt-like tools.
---
 mlir/include/mlir/Pass/PassManager.h          | 20 +++++++++++++++++++
 .../include/mlir/Tools/mlir-opt/MlirOptMain.h |  8 +-------
 mlir/lib/Pass/Pass.cpp                        |  8 ++++++++
 mlir/lib/Pass/PassCrashRecovery.cpp           | 17 ++++++++++++----
 mlir/lib/Pass/PassManagerOptions.cpp          |  8 ++++++++
 mlir/lib/Tools/mlir-opt/MlirOptMain.cpp       | 17 ----------------
 6 files changed, 50 insertions(+), 28 deletions(-)
diff --git a/mlir/include/mlir/Pass/PassManager.h b/mlir/include/mlir/Pass/PassManager.h
index 6e59b0f32ac6f..7f43c0e119403 100644
--- a/mlir/include/mlir/Pass/PassManager.h
+++ b/mlir/include/mlir/Pass/PassManager.h
@@ -222,12 +222,20 @@ struct ReproducerStream {
 using ReproducerStreamFactory =
     std::function<std::unique_ptr<ReproducerStream>(std::string &error)>;
 
+ReproducerStreamFactory makeReproducerStreamFactory(StringRef outputFile);
+
 std::string
 makeReproducer(StringRef anchorName,
                const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
                Operation *op, StringRef outputFile, bool disableThreads = false,
                bool verifyPasses = false);
 
+std::string
+makeReproducer(StringRef anchorName,
+               const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
+               Operation *op, const ReproducerStreamFactory &streamFactory,
+               bool disableThreads = false, bool verifyPasses = false);
+
 /// The main pass manager and pipeline builder.
 class PassManager : public OpPassManager {
 public:
@@ -282,6 +290,15 @@ class PassManager : public OpPassManager {
   /// Add the provided instrumentation to the pass manager.
   void addInstrumentation(std::unique_ptr<PassInstrumentation> pi);
 
+  /// Enable or disable the printing of pass manager reproducer.
+  void enableGeneratePassManagerReproducer(StringRef outputFile) {
+    forceGenerateReproducer = makeReproducerStreamFactory(outputFile);
+  }
+
+  void enableGeneratePassManagerReproducer(ReproducerStreamFactory factory) {
+    forceGenerateReproducer = std::move(factory);
+  }
+
   //===--------------------------------------------------------------------===//
   // IR Printing
 
@@ -492,6 +509,9 @@ class PassManager : public OpPassManager {
   llvm::hash_code pipelineInitializationKey =
       DenseMapInfo<llvm::hash_code>::getTombstoneKey();
 
+  /// A flag that indicates if the pass manager reproducer should be generated.
+  ReproducerStreamFactory forceGenerateReproducer;
+
   /// Flag that specifies if pass timing is enabled.
   bool passTiming : 1;
 
diff --git a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
index 0fbe15fa2e0db..9690ac6090fe7 100644
--- a/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
+++ b/mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h
@@ -237,10 +237,7 @@ class MlirOptMainConfig {
     return hasFilters;
   }
 
-  /// Reproducer file generation (no crash required).
-  StringRef getReproducerFilename() const { return generateReproducerFileFlag; }
-
-  /// Set the reproducer output filename
+  /// Set the remarks output filename
   RemarkFormat getRemarkFormat() const { return remarkFormatFlag; }
   /// Set the remark format to use.
   std::string getRemarksAllFilter() const { return remarksAllFilterFlag; }
@@ -340,9 +337,6 @@ class MlirOptMainConfig {
 
   /// Verify that the input IR round-trips perfectly.
   bool verifyRoundtripFlag = false;
-
-  /// The reproducer output filename (no crash required).
-  std::string generateReproducerFileFlag = "";
 };
 
 /// This defines the function type used to setup the pass manager. This can be
diff --git a/mlir/lib/Pass/Pass.cpp b/mlir/lib/Pass/Pass.cpp
index 521c7c6be17b6..7eabb62ec84ac 100644
--- a/mlir/lib/Pass/Pass.cpp
+++ b/mlir/lib/Pass/Pass.cpp
@@ -1033,6 +1033,14 @@ LogicalResult PassManager::run(Operation *op) {
        << size() << " passes, verifyPasses=" << verifyPasses << " pipeline: ";
     printAsTextualPipeline(os, /*pretty=*/false);
   });
+  // Generate reproducers if requested
+  if (forceGenerateReproducer) {
+    StringRef anchorName = getAnyOpAnchorName();
+    const auto &passes = getPasses();
+    makeReproducer(anchorName, passes, op, forceGenerateReproducer,
+                   /*disableThreads=*/!getContext()->isMultithreadingEnabled(),
+                   verifyPasses);
+  }
 
   MLIRContext *context = getContext();
   std::optional<OperationName> anchorOp = getOpName(*context);
diff --git a/mlir/lib/Pass/PassCrashRecovery.cpp b/mlir/lib/Pass/PassCrashRecovery.cpp
index 3c9735f910094..ba66d1df54d85 100644
--- a/mlir/lib/Pass/PassCrashRecovery.cpp
+++ b/mlir/lib/Pass/PassCrashRecovery.cpp
@@ -427,8 +427,8 @@ LogicalResult PassManager::runWithCrashRecovery(Operation *op,
   return passManagerResult;
 }
 
-static ReproducerStreamFactory
-makeReproducerStreamFactory(StringRef outputFile) {
+ReproducerStreamFactory
+mlir::makeReproducerStreamFactory(StringRef outputFile) {
   // Capture the filename by value in case outputFile is out of scope when
   // invoked.
   std::string filename = outputFile.str();
@@ -453,13 +453,22 @@ std::string mlir::makeReproducer(
     const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
     Operation *op, StringRef outputFile, bool disableThreads,
     bool verifyPasses) {
+  return makeReproducer(anchorName, passes, op,
+                        makeReproducerStreamFactory(outputFile), disableThreads,
+                        verifyPasses);
+}
 
+std::string mlir::makeReproducer(
+    StringRef anchorName,
+    const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
+    Operation *op, const ReproducerStreamFactory &streamFactory,
+    bool disableThreads, bool verifyPasses) {
   std::string description;
   std::string pipelineStr;
   llvm::raw_string_ostream passOS(pipelineStr);
   ::printAsTextualPipeline(passOS, anchorName, passes);
-  appendReproducer(description, op, makeReproducerStreamFactory(outputFile),
-                   pipelineStr, disableThreads, verifyPasses);
+  appendReproducer(description, op, streamFactory, pipelineStr, disableThreads,
+                   verifyPasses);
   return description;
 }
 
diff --git a/mlir/lib/Pass/PassManagerOptions.cpp b/mlir/lib/Pass/PassManagerOptions.cpp
index 305bf72bb4799..228a7716a114d 100644
--- a/mlir/lib/Pass/PassManagerOptions.cpp
+++ b/mlir/lib/Pass/PassManagerOptions.cpp
@@ -63,6 +63,11 @@ struct PassManagerOptions {
       llvm::cl::desc("When printing the IR before/after a pass, print file "
                      "tree rooted at this directory. Use in conjunction with "
                      "mlir-print-ir-* flags")};
+  llvm::cl::opt<std::string> generateReproducerFile{
+      "mlir-generate-reproducer",
+      llvm::cl::desc("Generate an mlir reproducer at the provided filename"
+                     " (no crash required)"),
+      llvm::cl::init(""), llvm::cl::value_desc("filename")};
 
   /// Add an IR printing instrumentation if enabled by any 'print-ir' flags.
   void addPrinterInstrumentation(PassManager &pm);
@@ -172,6 +177,9 @@ LogicalResult mlir::applyPassManagerCLOptions(PassManager &pm) {
 
   // Add the IR printing instrumentation.
   options->addPrinterInstrumentation(pm);
+
+  if (options->generateReproducerFile.getNumOccurrences())
+    pm.enableGeneratePassManagerReproducer(options->generateReproducerFile);
   return success();
 }
 
diff --git a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
index 30fd384f3977c..56932045a229d 100644
--- a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
+++ b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
@@ -198,15 +198,6 @@ struct MlirOptMainConfigCLOptions : public MlirOptMainConfig {
     static cl::list<std::string> passPlugins(
         "load-pass-plugin", cl::desc("Load passes from plugin library"));
 
-    static cl::opt<std::string, /*ExternalStorage=*/true>
-        generateReproducerFile(
-            "mlir-generate-reproducer",
-            llvm::cl::desc(
-                "Generate an mlir reproducer at the provided filename"
-                " (no crash required)"),
-            cl::location(generateReproducerFileFlag), cl::init(""),
-            cl::value_desc("filename"));
-
     static cl::OptionCategory remarkCategory(
         "Remark Options",
         "Filter remarks by regular expression (llvm::Regex syntax).");
@@ -568,14 +559,6 @@ performActions(raw_ostream &os,
   if (failed(pm.run(*op)))
     return failure();
 
-  // Generate reproducers if requested
-  if (!config.getReproducerFilename().empty()) {
-    StringRef anchorName = pm.getAnyOpAnchorName();
-    const auto &passes = pm.getPasses();
-    makeReproducer(anchorName, passes, op.get(),
-                   config.getReproducerFilename());
-  }
-
   // Print the output.
   TimingScope outputTiming = timing.nest("Output");
   if (config.shouldEmitBytecode()) {
    
    
More information about the Mlir-commits
mailing list