[PDL] Complex constraints in IR

I have been using PDL together with the Transform dialect for a while and found myself writing a lot of C++ code for matchers. Most of this is just fancy native op constraints and sometimes they are also quite similar.

E.g.: “Match all linalg.generic that are nested in an op of type X.”, with a native constraint for “nested in an op of type X”.

Are there any plans for custom constraints in IR? I was thinking of something along the lines of:

  • Add a new interface ApplyConstraintOpInterface, with ApplyNativeConstraintOp as one implementation that ships with PDL.
  • Users can provide their own ops that implement ApplyConstraintOpInterface via an external model.
  • ApplyConstraintOpInterface ops can be used in all places where ApplyNativeConstraintOp can be used at the moment.

I’m not sure how PDL works under hood (esp. PDLInterp), but does this make sense?
@River707

1 Like

I think this is a really good idea! ApplyNativeConstraintOp is a named function reference under the hood, so an interface could work the same way but instead use the op name and the interface method.

At this point I’d prefer to keep PDL constrained to just operations in the PDL dialect. Sharing constraint logic is something that should be better relegated to “libraries” of native constraints/rewrites, as opposed to new operations. Introducing interfaces at this point when things are still somewhat in flux feels a bit premature, and it isn’t clear that it’s the best way to solve this problem.

– River

I think the main benefit of doing this over native/generic constraints is stronger PDL-compile-time verification of constraint usage, which can be important if one has a large library of native constraints and rewrites.

That by itself is not compelling enough for me to start opening up the PDL ecosystem to external operations (e.g. given that we already do insert verification, albeit at match time at the moment, that checks input invariants. We could shift some of these checks offline if we wanted, but not all are static invariants). Allowing arbitrary operations is not something I take lightly, and it has to be strongly justified. For this feature, it’s not enough for me to warrant that shift, as opposed to exploring other avenues instead.

If you are using this in combination with the transform dialect, you can add ops with custom matching logic into a transform dialect extension, there is no requirement to use PDL at all for those.

If you are using this in combination with the transform dialect, you can add ops with custom matching logic into a transform dialect extension, there is no requirement to use PDL at all for those.

Yes, that’s what I am experimenting with now. A custom transform op (in IREE) that is basically just a matcher. It also makes the IR a bit more readable because I don’t need to wrap it in a pdl.pattern.