How to write conversion pattern with multiple ops?

Hi, I have a question about how to rewrite a conversion pattern when we have to convert a pattern with multiple ops at the same time.

image

For example, suppose we have a pattern (A + B) in dialect D1 and want to lower to pattern (A’ + B’) in dialect D2. D1 and D2 have different types (e.g. tensor vs memref). op A and op B have to be considered at same time in order to lower to D2.

There are some examples to show how to write RewritePattern with multiple ops. For ConversionPattern, it seems that the operands can not be accessed directly. How do we achieve this in ConversionPattern?

Can any one give some advice? Thanks!

Are A and B ops or patterns?

They are just simple ops. However, we must convert (A+B) at the same time for some reasons (e.g. B → B’ using the information from A).

The original operands are still present on the op using the normal operand accessors in addition to the rewritten operands being available as the operands argument to matchAndRewrite. So if your pattern would unconditionally lower A -> A' and then based on some information about A either lower B -> B' or B -> B", then that should work fine.

I don’t think this is possible right now, but I believe @River707 will enable this soon :wink:

There is some support right now, but it depends on what root operation you are matching. It’s also important to understand how the conversion process works in general. The conversion process ensures that all definitions are legalized before their uses, this means that when an operation B is visited, that it is fully legalized to the conversion target before moving on the operation A. If you want to rewrite operation A during the rewrite of operation B, there are a few things to keep in mind:

Operation B needs to properly dominate A

If B does not dominate A, A will be visited before.

Operation A cannot be the intermediate result of converting an operation that is dominated by B.

When legalizing a specific operation for the target, we perform a full legalization irregardless of how many steps that takes. This means that if operation A and B are intermediate results of converting a higher level form of operations, A won’t exist at the time of converting B. See the crude diagram below:

Say we have the following conversions that legalize D and D1 ti the conversion target:
DBB'
D1AA'

When we are legalizing D(and B/B' by extension), the only thing that exists in the IR is D1. We haven’t begun the legalization process of D1, so A and A' don’t exist yet.

Not all of the operands of A may have been converted.

Following from above, if there are operands of A that are between B and A they won’t have been converted at the time of converting B. If you know the operands were already converted, you can use ConversionPatternRewriter::getRemappedValue to get the rewritten value.

With that out of the way, if your use case does not break any of the above you could directly replace/erase/etc. A during the match of B and it should work as you expect. You should note however that all of the operations you generate when converting A will be legalized on the spot, and not deferred. The infra already has support for doing this given that it is common when lowering control flow region operations to remove the inner terminator when converting to a branch form. A good example is the lowering from SCF to Standard: llvm-project/SCFToStandard.cpp at d2c45f66204552177b164095501d560cd950a690 · llvm/llvm-project · GitHub