<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/54859>54859</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [MLIR] Dependent dialects of passes in dynamic pass pipelines are not loaded
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          rrbutani
      </td>
    </tr>
</table>

<pre>
    ## what

Since f9dc2b7079350d0fed3bb3775f496b90483c9e42, passes are encouraged to register the dialects they depend on with `getDependentDialects`. Dialects that are registered this way are then loaded by [`PassManager::run`](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/lib/Pass/Pass.cpp#L663-L668) (which ultimately [calls `OpToOpPassAdaptor::runPipeline`](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/lib/Pass/Pass.cpp#L393-L395) to actually run the passes in the pipeline).

This works well for ordinary pass pipelines but doesn't seem to work for _dynamic_ pass pipelines that are added using [`Pass::runPipeline`](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/include/mlir/Pass/Pass.h#L191-L196). Pipelines that are run this way are executed via the registered [`pipelineExecutor`](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/include/mlir/Pass/Pass.h#L195) ([this lambda](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/lib/Pass/Pass.cpp#L376-L395)) which then calls [`OpToOpPassAdaptor::runPipeline`](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/lib/Pass/Pass.cpp#L393) without loading dependent dialects. This leads to errors when dynamic pass pipeline passes try to use their dependent dialects.

Is this intended behavior? If not, it _seems_ like adding [these lines](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/lib/Pass/Pass.cpp#L663-L668) to [`dynamicPipelineCallback`](https://github.com/llvm/llvm-project/blob/64d3e163d8e35d2d67e060c1bd5a1f1e8d7cfa8f/mlir/lib/Pass/Pass.cpp#L388) would yield the expected behavior.

## example

Here's a small program that reproduces the error:
```c++
#include "mlir/Dialect/AMX/AMXDialect.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/DialectRegistry.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Parser/Parser.h"
#include "mlir/Pass/PassManager.h"

namespace m = mlir;

struct PassWithDependentDialects
    : public m::PassWrapper<PassWithDependentDialects,
                               m::OperationPass<m::func::FuncOp>> {
  void getDependentDialects(m::DialectRegistry &registry) const override {
    llvm::errs() << "! PassWithDependentDialects deps\n";
    registry.insert<m::amx::AMXDialect>();
  }

  void runOnOperation(void) override {
    m::OpBuilder b(getOperation());
    b.create<m::amx::TileZeroOp>(
        /* loc: */ getOperation()->getLoc(),
        /* ret: */ m::VectorType::get({1, 1}, b.getF32Type())
    );
  }
};

struct ExamplePass
    : public m::PassWrapper<ExamplePass,
                               m::OperationPass<m::ModuleOp>> {

  static std::unique_ptr<m::OperationPass<m::ModuleOp>> create() {
    return std::make_unique<ExamplePass>();
  }

  void getDependentDialects(m::DialectRegistry &_registry) const override {
    llvm::errs() << "! ExamplePass deps\n";
  }

  void runOnOperation(void) override {
    m::ModuleOp f = getOperation();
    m::OpPassManager pipeline(m::ModuleOp::getOperationName());

    pipeline.nest<m::func::FuncOp>().addPass(std::make_unique<PassWithDependentDialects>());

    if (m::failed(runPipeline(pipeline, f.getOperation()))) {
      return signalPassFailure();
    }
  }
};

int main(int argc, char **argv) {
  m::MLIRContext context;
  context.getOrLoadDialect<m::func::FuncDialect>();

  auto input = R"(
    module {
      func.func @test(%x: i64) -> i64 {
        return %x : i64
      }
    }
  )";
  m::OwningOpRef<m::ModuleOp> module = m::parseSourceString<m::ModuleOp>(input, &context);

  m::PassManager pm(&context);
  pm.addPass(ExamplePass::create());

  if (m::failed(pm.run(module.get()))) {
    module->emitError();
    return 1;
  }

  module->dump();
}
```

`PassWithDependentDialects` is a (nonsensical) pass that makes use of an unregistered dialect; despite registering it in its `getDependentDialects` method, it encounters a runtime error when trying to create an op in the `AMX` dialect.

### example, as a Bazel workspace

[Here](https://github.com/llvm/llvm-project/files/8469736/dynamic-pipeline-example.zip) is a nix flake/Bazel workspace with the above (`nix develop` + `bazel run //:example`).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzVWUtv4zgS_jXKhYghS37p4ENsdzANdE8a6cbuYi8BJVI2p_Uaikri-fXzFUVZcqJkkkUfsoEgyRRZ7_qKxcSlOK69IMTFHg7ceP7O86_a-3dVJJKlkUiCeOkvo3DuCz-VIozjcLmcp7NoEUf-bBUmkZwFXrBlFa9rWTOuJZNFUjaa76VgpmRa7lVtpGbmIJlQPJOJqenHkQlZyUKwsmAPyhyYt_D30uzsoCzMzs3F8ITt-oXcWC4dXeJyUDV74Ec7DsoFy0ou8CE-Mm--AYFvkO4rLyCT9sIrXLopMOzNd16wOhhT1TQcXOPaQ5QmniRljh9Zdt89Litd_gER8DPOyhiPxUyEcroIxUqGcxGIxVL6Cz-ZxmLOp-lUrsQySfkqxdQ8U5roKFpHwrjHJKkq2P_LYhFe4rbygohBooeDSg6syYzKuZGZ1SLhWVaTjW6qH-VNRauvBK9M2Wv0TVUyU4X8SJqFETQLozlphmjgiWmgyJFBXBsRLm6U-9VpEESTYTz-sB4u9U_cZZaxtNSs1EIVXB8tidPKmsWNYaKUdeEFS8NqKXNiTIvtsjtxLHiukrun606RxQXFTlOrYj8In49gZWRl1gjZDwwNfiBzT6PpJW4LMiD79ly31uyDdJGPMmkM9L1X3LpgkFet8p2FPtmZCLePqffc5Q6EtgpmPI8F_zh5sFx0eUCCthluscoltrX1_11uW13Au0TSEehSzogOwU9wP2E2gTPJRU3JKLUuNWKQ1HfpeJ6NHSwYpDfmN7XFdaXHaA9x4nPdRrcqDE1DBZAHfq_Ijtfsc8qK0lCxUobdETDUdyxTP23Gu2QHF_CySfNhzDwsDjBGGynObF1YbBFEMU9-fqjwWFmRH8omE-yoZCYswMjHChwHvjnzoNuQyEeeV5kcfvkNmARIxx6D1TnUZZB9r3negpuW-CmaxIKdbCOM1G8JwCr2SrxgQ1fHygELcCNw2riNBt6uvv6nvbshAprgTSuvmwKMrj_fuvebqv6nxXbuplEo-cWVMVqhisl3rXonkx_H6o3036j-cO6trSH6-KY1X798vt2WSNjHf-TxBPZfn6pr2b-8g7LbJw5X2DvyTdYVx744Z164Y3ZluBlOgc5NYhhR-Tcy7vlW1s5i-ENosqqJMwBf3mK8XaR5VdEWdfsyiWDbU3nlz1G9ATluVFm0W5itG04pQu1bG59e-AkX85abjvh9qQQb3Y4HK0fkibNhzYV275T3SVnUhpX3SEVFtu5pM2YhyBLBVyJpi3e4xUVO8YLpy0akGgBw3hY0MRwQ7ZhPVAGPm15bnj-2L30yk8KW64CCt9wNnelsgNp7U5zMiEU0SuKOa3ayO-WZQNsDcFzBjkMK7R7gTHZgs5bY648I_UNl8r9Sl62XsPrM_Rbfr1B7yZ_4RYDPnvO7xFqMfsE0x387SkdLM6DjRPkXDFZqQoz2NwgRleVmSsV0SnbDM55g_DoM7LyTkn3Ev2BrvIwm0ae2Ati4fXPaDBf9kkT5ipqSyecJ0pGuDRYleIh2flOoPxt5Vxnd03gbaed_lwrLs7g2jS56Hjn_Ke9aRk9UfnNQvzux735hZg8kfiGXf2UmdmZmqUXtkVQMx9J3UAkGXenqme9cPpxo_o4q8TzFewYdrQl2mOZ1QLZUJtibtuG8eiEAXi4Vp3AYlUSlrFco5UAZGHM1bDWCVa_5lqWTcRhrG5oz0_cxq_YFz0jCazBotBwx-cnZr6ICdvQs54r40ivX-4SESg5ct2h1haH7J5J03up3GBS79BxI4EasdvoLephTiRh3zosVpCPI0SWjA6nQElHE3dqwH8B2boPnqcWIyYRuzJv5hoKDqM-pCDC1mJFmBOL0_nTpydw0n3ULBhMGJj63N_lumHhd-D8U6IduqluZjuLVSQXaBrVfK9pmfS8bncjv2L4W-3GgI-_BMOQ6oErnjBEjDuD9lIa5NcnYKuRVPsiUM0wkMkNwHeM2ngugSeeE-GA1mLi692LYt9PISzJX5pNtQZ7Hu_PV9DW86ymJJq-extlpdtfWnDVQ7XHVOCIsfKaogQLFAiAui1olPCNFbPttOylCl9q23GXKeMGaYnAkJLrg3wC660qZ_sCIOmg01qrAvX7lMJfl0hxK4fpwe1gMf2oSC9Y2KnfdW3s8gJJDhJFRrQ9JorLqzgtBjto0EHWCjfSSw3YSPDkx2vC_ZNYeKNKO_mzRfGM7zf-ti04ROtRIrGaLaBku8OYa9csOSi-dLJO_VEWGt_4o1CNLMxieGrRz2dqzcVKWxyh09ohr4dMCIe9lVlakPXpaskVsl9IZXyswVWGnOYIExeRCrEMRhRG_MMpkcg1lCRyhLNs9O1kh__fHs6PnNO2Bf1Ead-J-0ehs_W6jqbpurNXms9U8ujisRTpPw3nE6V8M0k_iKJrPwkAEQbiQs0iuLjIey6wm8YFfhXxglgRh2Xx3odaBHwT-bBr48-ks9Cd-HHPprwTHI13BKzNfopZkE5JjUur9hV5bkeJmX-Njhniu-49QGGVMWmsRfeD7odRrrdGj80JdWN5rK_vfEKmp5w">