Enforcing conversion pattern order with root updates

Hello everyone.
Right now I am working on a dialect quite similar to CIRCT’s FIRRTL, converting generic operations like add to instances of modules in FIRRTL.

Because of the difference in the outputs of a generic add operations (a single value) and firrtl.instance operation (N inputs and K outputs), I had to directly specify which of the outputs is equivalent to the one before the conversion using ConversionPatternRewriter.replaceAllUsesWith, but this means that in-place root updates will appear, processing operations out of initial order.

Because of that some operands for the operation participating in the in-place root update might not be converted yet, which causes unrealized_conversion_cast-operations to appear.

Given the context is there any way to enforce the rule that the operands are always processed before the operation itself so it is possible to evade any unrealized_conversion_casts? I tried to look in the way of target materializations, but if I understood them correctly, it creates additional operation, which are similar to unrealized_conversion_casts in their purpose.

Maybe there are other ways of replacing all SSA-value’s uses without having to invoke in-place legalization pattern application, but I am afraid after looking into the problem for a while I couldn’t find them.