This change fixes a bug where a dialect is initialized multiple times. This triggers an assertion when the ops of the dialect are registered (error: operation named ... is already registered).
This bug can be triggered as follows:
- Dialect A depends on dialect B (as per ADialect.td).
- Somewhere there is an extension of dialect B that depends on dialect A (e.g., it defines external models create ops from dialect A). E.g.:
registry.addExtension(+[](MLIRContext *ctx, BDialect *dialect) { BDialectOp::attachInterface ... ctx->loadDialect<ADialect>(); });
- When dialect A is loaded, its initialize function is called twice:
ADialect::ADialect() | | | v | ADialect::initialize() v getOrLoadDialect<BDialect>() | v (load extension of BDialect) | v ctx->loadDialect<ADialect>() // user wrote this in the extension | v getOrLoadDialect<ADialect>() // the dialect is not "fully" loaded yet | v ADialect::ADialect() | v ADialect::initialize()
An example of a dialect extension that depends on other dialects is Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp. That particular dialect extension does not trigger this bug. (It would trigger this bug if the SCF dialect would depend on the Tensor dialect.)
This change introduces a new dialect state: dialects that are currently being loaded. Same as dialects that were already fully loaded (and initialized), dialects that are in the process of being loaded are not loaded a second time.
This doesn't look like something that should be publicly exposed.