Linalg intermediate IR error

Hi all,
While debugging this error, I met another problem while trying to print intermediate lowering from Linalg to LLVM.

I am trying to optimize a single Linalg.Matmul operator.

This is the sequence of passes I am using:

    funcPM.addPass(mlir::createCanonicalizerPass());
    funcPM.addPass(createLinalgCodegenPass(options));

    // Run the passes and print the intermediate MLIR module

    funcPM.addPass(mlir::createConvertVectorToSCFPass());
    funcPM.addPass(mlir::createLowerAffinePass());
    funcPM.addPass(mlir::createConvertLinalgToLoopsPass());

Now, I would like to print the intermediate IR after createLinalgCodegenPass, which is a pass I created (following mmperf) that basically tiles/promotes/vectorizes the operation.

However, when I run the pass manager after createLinalgCodegenPass (as shown in the snippet) I get this error:
LLVM ERROR: Building op `vector.transfer_read` but it isn't registered in this MLIRContext

I have registered the Vector dialect and I am also allowing unregistered ops. If I run the passes after the createLowerAffinePass, everything works, but I am not able to see the intermediate IR. Why is it raising this error?

Thanks for any hint,
Giuseppe

This error usually means that the pass does not declare the relevant dialect (vector in this case) as dependent. See FAQ - MLIR. Registering a dialect with the context does not automatically make its operations registered. (The terminology is confusing here).

Hi @ftynse,
Thank you so much for your help, it works now. Can I ask more about the difference between Loading a dialect and declaring it as dependent from a pass?

I was indeed loading all dialects in the context, but I was not inserting the VectorDialect in the registry during getDependentDialects. Why is this necessary? The FAQ says:

The process of loading a Dialect in the context is not thread-safe, which forces all involved Dialects to be loaded before the multi-threaded pass manager starts the execution. To keep the system modular and layered, invoking a pass pipeline should never require pre-loading dialects explicitly. This is achieved by requiring every pass to declare a list of dependent Dialects: these are Dialects for which an entity (Operation, Type, or Attribute) can be created by the pass, other than for Dialects that would already be in the input.

Does it mean that when I load a dialect into the context I am not loading its operations? So those operations only get loaded from within the pass?

Thank you once more for the help,
Giuseppe

This is rather peculiar. Listing a dialect as dependent in a pass makes pass manager load this dialect before it runs the pipeline. If the dialect is already loaded (being registered is not sufficient), this should not be necessary. There may be something going on with multiple contexts, linkage-level registration or ordering (e.g., the vector dialect is not registered with the context when loadAllAvaiableDialects is called).

So I am not running on the latest version of LLVM (but we have a pinned version we use). What I do is:

    mlir::MLIRContext context;
    auto registry = context.getDialectRegistry();
    registerAllDialects(context.getDialectRegistry());
    context.allowUnregisteredDialects(true);
    context.printOpOnDiagnostic(true);
    registry.loadAll(&context);

Is that the same of calling context.loadAllAvailableDialects()?

Looks like it should be the same, but hard to be certain without knowing the exact version.

@mehdi_amini may know better, he wrote the dialect management piece.

Coincidentally, we just ran into a similar-looking issue in Cuda backend build failure · Issue #6979 · google/iree · GitHub. I’m glad this thread was just here because I also assumed it was an issue with not having registered the GPU dialect, which I was pretty sure we’d registered. Could we add a hint to that error message like “Has its dialect been loaded?” to indicate the problem is likely from having failed to load the necessary dialect?

And a link to a nice little FAQ about register vs load of dialects. That works really well e.g. for LLD when it points you to Missing Key Function — lld 14 documentation

context.loadAllAvailableDialects() will load all the dialects that are registered with the context, while registry.loadAll(&context); will load the dialects registered in this particular registry with the provided context. Other dialects previously registered with the context, but not in this particular registry won’t be loaded.

In general for a “production” system (I’d say anything that is more than quick prototyping) should never have to explicitly load any dialect (other than the one emitted programmatically by a frontend).
(Similarly, I avoid allowUnregisteredDialects as much as possible beyond prototyping).

That’s a good idea!
I’m slightly nervous about the lack of stability of URLs (It may be why Microsoft and others are using error codes instead, it is easier to manage the redirection as well).

1 Like

Can we set up a redirect on, e.g, http://mlir.dev/errorcode/42 ?

1 Like

Yeah we should work on something like this! @jpienaar : thoughts?

That would be really cool!