where we may assume that all these SSA values are defined prior to this IfOp of course. This is totally fine and works as expected. However, if we move %value inside the IfOp as follows:
Even though I have defined a converter for my custom foo.op which works in the first case, however, it doesn’t seem to kick-in in the second case.
In fact, even if I call target.addLegalOp<FooOp>() I still get the same error.
I can’t speak to this specific failure, but you’ll probably want to run this with --debug-only=dialect-conversion, which will provide helpful output about all the patterns the conversion framework attempts to apply and their success/failure. See Debugging Tips - MLIR and Dialect Conversion - MLIR
The --debug-only=dialect-conversion definitely helped!
I think I have narrowed down the issue. The issue is related to type materialization so in order to reproduce you would need an op that may return a non-signless integer type like si16 or ui16. I’ll try to create a reproducible test asap.
In the meantime, what happens is that the converter will produce an llvm.mlir.cast (or LLVM::DialectCastOp) to cast the si16/ui16 types to i16. It seems that this materialization falls into some kind of infinite loop. Here is the relevant part of the log:
As you can see, a daisy-chain of llvm.mlir.cast ops is created which is thankfully stopped by the infrastructure (it detects whether a given pattern is applied already). Otherwise, I think it might have fallen into an infinite loop.
Thank you all! Alex, I think that settles it for me. Adjusting my foo custom dialect to be signless solved the issue. However, I was wondering … should I still file a bug report for this to make the failure more clear (as opposed to failing subtly) ? For example, should the type materializer throw an error when a signed/unsigned int is encountered instead of trying to convert it assuming its OK ?
That would require non-trivial changes, and cannot say outright if it is even feasible.
Most conversion passes are partial conversions, meaning that as long as the result does not contain ops declared illegal in the conversion target, they succeed. The expectation is that some further conversion will deal with the remaining ops. This is a conscious design decision, otherwise we risk running into the monolithic all-to-one-dialect conversions quickly.
The fact that a specific conversion does not know how to convert specific types does not and should not mean conversion failure. Some patterns may fail to match, other patterns may be more forgiving and adapt.
Materialization hooks are there to inject opaque casts. They are not currently configured to cast from (un)signed to singless integers but they could be. And some further pass may eliminate those.
So the actual error would be something like “the conversion infra couldn’t convert the type, which led to all potentially applicable patterns not being applied (list of reasons for each pattern), which led to source materialization, which injected an llvm.mlir.cast op of a form that is illegal; abort”. This kind of logic reasoning feels hard to build.