And the other tries to build the same MLIR explicitly (using mlirOperationCreate and friends). Both end up creating a module with the following generic form:
The second looks to me like the standard dialect has not been loaded into the context in the right way. I’d have to dig up the details, but I think the parser does something special to load dialects when an op is encountered, whereas if you are building it yourself, this does not happen.
In any case, I would look at the code you are using to load/register dialects.
It looks like the issue on my end was that I was registering the dialect, but not loading it (I’m not sure what the distinction is here). The reason this wasn’t a problem before is because I happened to always parse before constructing and not switching to a new context in-between.
I believe that registering just creates a mapping between the namespace and a lambda that initializes the dialect. Loading actually performs the initialization. Some dialects have thousands of ops and other heavy weight initialization sequences, and there is a desire for tools like mlir-opt to be able to have both light weight registration of everything and still be able to do on demand initialize/load. For domain specific use when you know what you are building, just always load everything you care about.