[mlir][PDL] Relax PDL verification constraints
This commit introduces the following changes:
1. HasParentNotOf: A trait that verifies an operation's parent is not one of
the specified parent operations.
2. Adds a `nonmaterializable` attribute to `pdl.pattern`
that indicates a pattern cannot be directly lowered to pdl_interp. This
allows patterns to contain non-PDL operations (e.g., func.call), and relax
other constraint for when a pattern requires further transformations before
materialization. An example, of such transformation is function inlining on
the example below.
3. Relax parent constraints in PDL. For example, instead of `HasParent<RewriteOp>`
use `HasParentNotOf<PatternOp>`, as the latter has the same intended meaning within
PDL, but allows using the ops outside PDL like in func.func.
4. Add error in PDLToPDLInterp pass for nonmaterializable patterns. It's responsibility
of the user to make un-materializable patterns materializable before conversion to
`pdl_interp`
Example:
```mlir
func.func @pattern_body() -> (!pdl.type, !pdl.type, !pdl.operation) {
%type1 = pdl.type : i32
%type2 = pdl.type
%root = pdl.operation -> (%type1, %type2 : !pdl.type, !pdl.type)
return %type1, %type2, %root : !pdl.type, !pdl.type, !pdl.operation
}
func.func @rewrite_body(%type1: !pdl.type, %type2: !pdl.type, %root: !pdl.operation) {
%newOp = pdl.operation "foo.op" -> (%type1, %type2 : !pdl.type, !pdl.type)
pdl.apply_native_rewrite "NativeRewrite"(%newOp, %root : !pdl.operation, !pdl.operation)
return
}
pdl.pattern @nonmaterializable_pattern : benefit(1) nonmaterializable {
%type1, %type2, %root = func.call @pattern_body()
: () -> (!pdl.type, !pdl.type, !pdl.operation)
rewrite %root {
func.call @rewrite_body(%type1, %type2, %root)
: (!pdl.type, !pdl.type, !pdl.operation) -> ()
}
}
```
Signed-off-by: Fabian Mora <fabian.mora-cordero@amd.com>