Better documenting and surfacing of patterns

Hi everyone,

As more and more of our transformations evolve towards composition of orthogonal patterns, I find it more and more important to be able to document and surface these properly.

Today I would argue that MLIR infra has good support for this in the context of Passes with all the ODS related stuff. I would love to have something similar to automate the documentation, visibility and grouping of individual patterns into coherent sets.

Note that sets of patterns may well overlap to produce different transformations and that is ok.
I am thinking this would also be an opportunity to explore setting benefits in a more flexible and usable way. Indeed benefits are not really a frozen property of a pattern but rather a property of a pattern when used in conjunction with other patterns.

Bonus points would be the automation of creating passes by just assembling sets of patterns to be applied in sequence (one set at a time), in a declarative fashion.

Has someone thought about this level of control and/or has ideas to propose on the topic?

1 Like

With the Standard dialect finally on its deathbed, there is a question of what to do with the StandardTo* and *ToStandard passes. Splitting the passes into passes that work individually can be tricky because of transiently invalid ops or bidirectional dependencies between passes, but what’s worse is

mlir-opt --convert-arith-to-llvm --convert-tensor-to-llvm \
    --convert-memref-to-llvm --convert-math-to-llvm \
    --convert-func-to-llvm --cf-to-llvm ...

Which prompted the idea of “structure pipelines/passes” from @River707

I also have been thinking for a while that we should have “pattern groups” which would, as you say, represent “compositions of patterns”, on top of which one could build a declarative way to construct passes. Could be as simple as:

def PatternGroupA : PatternGroup<[PatternA, PatternB, ...], (benefit 0)>;

Another small use case of “pattern groups” would be more “granularity” in the patterns I define in a TD file. E.g. currently all patterns defined in a single TD file are thrown into one populate*Patterns functions. If I want to write a bunch of canonicalization patterns, I have to name them and add them individually. With groups maybe I can do

patterns.insert<AddIOpCanonicalizationPatterns>(context);
1 Like

Over in circt we’ve been running into the issue of needing sequential pattern application for various conversion passes. Here, we’ve also been working with the concept of partial lowering - which essentially is a hack around some of the restrictions of the pattern rewrite infrastructure that allows us to use rewriters and forward success/failure states while relaxing the requirement that matched/converted operations must be replaced.

An example use is in SCFToCalyx where a bunch of partial lowering patterns are specified and applied sequentially:

Operations don’t need to be replaced. They could also be erased, or updated-in-place(which could even do nothing but mark a flag somewhere else).

– River

That sounds like it would a nice doc contribution!

Patterns are an expression of equality under constraints indeed.

in conjuction with a build rule. So one can do subincludes of TD files of patterns etc, the cost is generating duplicate code, where this would avoid it. [I’m not sure how benefit on patterngroup would work and interact with benefit on patterns, esp if each pattern group is used as a pass and or we could have the same pattern in multiple groups]. PatternGroup (or Set as there is no ordering of pattern applications) would also get us to defining pretty much a complete pass in ODS (which has been on my wishlist).

That is slightly orthogonal to the doc part: I’d like to have all patterns listed. Basically (seeing as visualization is being discussed tomorrow :wink: ) this could be a graph of conversion patterns, or dictionary of them indexed on root note & file defined in. Which would document & make it discoverable.

1 Like