[all-commits] [llvm/llvm-project] dca32a: [mlir][PDL] Add support for native constraints wit...

Matthias Gehre via All-commits all-commits at lists.llvm.org
Thu Feb 29 22:30:00 PST 2024


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: dca32a3b594b3c91f9766a9312b5d82534910fa1
      https://github.com/llvm/llvm-project/commit/dca32a3b594b3c91f9766a9312b5d82534910fa1
  Author: Matthias Gehre <matthias.gehre at amd.com>
  Date:   2024-03-01 (Fri, 01 Mar 2024)

  Changed paths:
    M mlir/include/mlir/Dialect/PDL/IR/PDLOps.td
    M mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterpOps.td
    M mlir/include/mlir/IR/PDLPatternMatch.h.inc
    M mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
    M mlir/lib/Conversion/PDLToPDLInterp/Predicate.h
    M mlir/lib/Conversion/PDLToPDLInterp/PredicateTree.cpp
    M mlir/lib/Dialect/PDL/IR/PDL.cpp
    M mlir/lib/Rewrite/ByteCode.cpp
    M mlir/lib/Tools/PDLL/Parser/Parser.cpp
    M mlir/test/Conversion/PDLToPDLInterp/pdl-to-pdl-interp-matcher.mlir
    A mlir/test/Conversion/PDLToPDLInterp/use-constraint-result.mlir
    M mlir/test/Dialect/PDL/ops.mlir
    M mlir/test/Rewrite/pdl-bytecode.mlir
    M mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp
    M mlir/test/lib/Rewrite/TestPDLByteCode.cpp
    M mlir/test/mlir-pdll/Parser/constraint-failure.pdll
    M mlir/test/mlir-pdll/Parser/constraint.pdll
    M mlir/test/python/dialects/pdl_ops.py

  Log Message:
  -----------
  [mlir][PDL] Add support for native constraints with results (#82760)

>From https://reviews.llvm.org/D153245

This adds support for native PDL (and PDLL) C++ constraints to return
results.

This is useful for situations where a pattern checks for certain
constraints of multiple interdependent attributes and computes a new
attribute value based on them. Currently, for such an example it is
required to escape to C++ during matching to perform the check and after
a successful match again escape to native C++ to perform the computation
during the rewriting part of the pattern. With this work we can do the
computation in C++ during matching and use the result in the rewriting
part of the pattern. Effectively this enables a choice in the trade-off
of memory consumption during matching vs recomputation of values.

This is an example of a situation where this is useful: We have two
operations with certain attributes that have interdependent constraints.
For instance `attr_foo: one_of [0, 2, 4, 8], attr_bar: one_of [0, 2, 4,
8]` and `attr_foo == attr_bar`. The pattern should only match if all
conditions are true. The new operation should be created with a new
attribute which is computed from the two matched attributes e.g.
`attr_baz = attr_foo * attr_bar`. For the check we already escape to
native C++ and have all values at hand so it makes sense to directly
compute the new attribute value as well:

```
Constraint checkAndCompute(attr0: Attr, attr1: Attr) -> Attr;

Pattern example with benefit(1) {
    let foo = op<test.foo>() {attr = attr_foo : Attr};
    let bar = op<test.bar>(foo) {attr = attr_bar : Attr};
    let attr_baz = checkAndCompute(attr_foo, attr_bar);
    rewrite bar with {
        let baz = op<test.baz> {attr=attr_baz};
        replace bar with baz;
    };
}
```
To achieve this the following notable changes were necessary:
PDLL:
- Remove check in PDLL parser that prevented native constraints from
returning results

PDL:
- Change PDL definition of pdl.apply_native_constraint to allow variadic
results

PDL_interp:
- Change PDL_interp definition of pdl_interp.apply_constraint to allow
variadic results

PDLToPDLInterp Pass:
The input to the pass is an arbitrary number of PDL patterns. The pass
collects the predicates that are required to match all of the pdl
patterns and establishes an ordering that allows creation of a single
efficient matcher function to match all of them. Values that are matched
and possibly used in the rewriting part of a pattern are represented as
positions. This allows fusion and thus reusing a single position for
multiple matching patterns. Accordingly, we introduce
ConstraintPosition, which records the type and index of the result of
the constraint. The problem is for the corresponding value to be used in
the rewriting part of a pattern it has to be an input to the
pdl_interp.record_match operation, which is generated early during the
pass such that its surrounding block can be referred to by branching
operations. In consequence the value has to be materialized after the
original pdl.apply_native_constraint has been deleted but before we get
the chance to generate the corresponding pdl_interp.apply_constraint
operation. We solve this by emitting a placeholder value when a
ConstraintPosition is evaluated. These placeholder values (due to fusion
there may be multiple for one constraint result) are replaced later when
the actual pdl_interp.apply_constraint operation is created.

Changes since the phabricator review:
- Addressed all comments
- In particular, removed registerConstraintFunctionWithResults and
instead changed registerConstraintFunction so that contraint functions
always have results (empty by default)
- Thus we don't need to reuse `rewriteFunctions` to store constraint
functions with results anymore, and can instead use
`constraintFunctions`
- Perform a stable sort of ConstraintQuestion, so that
ConstraintQuestion appear before other ConstraintQuestion that use their
results.
- Don't create placeholders for pdl_interp::ApplyConstraintOp. Instead
generate the `pdl_interp::ApplyConstraintOp` before generating the
successor block.
- Fixed a test failure in the pdl python bindings


Original code by @martin-luecke

Co-authored-by: martin-luecke <martinpaul.luecke at amd.com>



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list