'pdl' Dialect
High level pattern definition dialect PDL presents a high level abstraction for the rewrite pattern infrastructure available in MLIR. This abstraction allows for representing patterns transforming MLIR, as MLIR. This allows for applying all of the benefits that the general MLIR infrastructure provides, to the infrastructure itself. This means that pattern matching can be more easily verified for correctness, targeted by frontends, and optimized.
PDL abstracts over various different aspects of patterns and core MLIR data
structures. Patterns are specified via a pdl.pattern
operation. These
operations contain a region body for the “matcher” code, and terminate with
a pdl.rewrite
that either dispatches to an external rewriter or contains
a region for the rewrite specified via pdl
. The types of values in pdl
are handle types to MLIR C++ types, with !pdl.attribute
, !pdl.operation
,
and !pdl.type
directly mapping to mlir::Attribute
, mlir::Operation*
,
and mlir::Value
respectively.
An example pattern is shown below:
// pdl.pattern contains metadata similarly to a `RewritePattern`.
pdl.pattern : benefit(1) {
// External input operand values are specified via `pdl.input` operations.
// Result types are constrainted via `pdl.type` operations.
%resultType = pdl.type
%inputOperand = pdl.input
%root, %results = pdl.operation "foo.op"(%inputOperand) -> %resultType
pdl.rewrite %root {
pdl.replace %root with (%inputOperand)
}
}
The above pattern simply replaces an operation with its first operand. Note how the input operation is specified structurally, similarly to how it would look in memory. This is a simple example and pdl provides support for many other features such as applying external constraints or external generator methods. These features and more are detailed below.
Type constraint definition ¶
PDL handle to an mlir::Attribute
¶
This type represents a handle to an instance of an mlir::Attribute
, bound
to a value that is usable within a PDL pattern or rewrite.
PDL handle to an mlir::Operation *
¶
This type represents a handle to an instance of an mlir::Operation *
,
bound to a value that is usable within a PDL pattern or rewrite.
PDL handle to an mlir::Type
¶
This type represents a handle to an instance of an mlir::Type
, bound to a
value that is usable within a PDL pattern or rewrite.
PDL handle for an mlir::Value
¶
This type represents a handle to an instance of an mlir::Value
, bound to a
value that is usable within a PDL pattern or rewrite.
Operation definition ¶
pdl.apply_constraint
(::mlir::pdl::ApplyConstraintOp) ¶
Apply a generic constraint to a set of provided entities
Syntax:
operation ::= `pdl.apply_constraint` $name ($constParams^)? `(` $args `:` type($args) `)` attr-dict
apply_constraint
operations apply a generic constraint, that has been
registered externally with the consumer of PDL, to a given set of entities.
The constraint is permitted to accept any number of constant valued
parameters.
Example:
// Apply `myConstraint` to the entities defined by `input`, `attr`, and
// `op`. `42`, `"abc"`, and `i32` are constant parameters passed to the
// constraint.
pdl.apply_constraint "myConstraint"[42, "abc", i32](%input, %attr, %op : !pdl.value, !pdl.attribute, !pdl.operation)
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
constParams | ::mlir::ArrayAttr | array attribute |
Operands: ¶
Operand | Description |
---|---|
args | Positional Value |
pdl.attribute
(::mlir::pdl::AttributeOp) ¶
Define an input attribute in a pattern
Syntax:
operation ::= `pdl.attribute` attr-dict (`:` $type^)? ($value^)?
pdl.attribute
operations capture named attribute edges into an operation.
Instances of this operation define, and partially constrain, attributes of a
given operation. A pdl.attribute
may partially constrain the input by
specifying an expected attribute value type (via a pdl.type
operation), or
a constant value for the attribute (via val
). Only one of these may be set
for a given input, as the type of the constant value provides the type. When
defined within a pdl.rewrite
region, the constant value must be specified.
Example:
// Define an attribute:
%attr = pdl.attribute
// Define an attribute with an expected type:
%type = pdl.type : i32
%attr = pdl.attribute : %type
// Define an attribute with a constant value:
%attr = pdl.attribute "hello"
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
value | ::mlir::Attribute | any attribute |
Operands: ¶
Operand | Description |
---|---|
type | PDL handle to an mlir::Type |
Results: ¶
Result | Description |
---|---|
attr | PDL handle to an mlir::Attribute |
pdl.create_native
(::mlir::pdl::CreateNativeOp) ¶
Call a native creation method to construct an Attribute
, Operation
, Type
, or Value
Syntax:
operation ::= `pdl.create_native` $name ($constParams^)? (`(` $args^ `:` type($args) `)`)? `:` type($result)
attr-dict
pdl.create_native
operations invoke a native C++ function, that has been
registered externally with the consumer of PDL, to create an Attribute
,
Operation
, Type
, or Value
. The native function must produce a value
of the specified return type, and may accept any number of positional
arguments and constant attribute parameters.
Example:
%ret = pdl.create_native "myNativeFunc"[42, "gt"](%arg0, %arg1) : !pdl.attribute
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
constParams | ::mlir::ArrayAttr | array attribute |
Operands: ¶
Operand | Description |
---|---|
args | Positional Value |
Results: ¶
Result | Description |
---|---|
result | Positional Value |
pdl.erase
(::mlir::pdl::EraseOp) ¶
Mark an input operation as erased
Syntax:
operation ::= `pdl.erase` $operation attr-dict
pdl.erase
operations are used within pdl.rewrite
regions to specify that
an input operation should be marked as erased. The semantics of this
operation correspond with the eraseOp
method on a PatternRewriter
.
Example:
pdl.erase %root
Operands: ¶
Operand | Description |
---|---|
operation | PDL handle to an mlir::Operation * |
pdl.input
(::mlir::pdl::InputOp) ¶
Define an input value in a pattern
Syntax:
operation ::= `pdl.input` (`:` $type^)? attr-dict
pdl.input
operations capture external operand edges into an operation
node that originate from operations or block arguments not otherwise
specified within the pattern (e.g. via pdl.operation
). These operations
define, and partially constrain, input operands of a given operation.
A pdl.input
may partially constrain an input operand by specifying an
expected value type (via a pdl.type
operation).
Example:
// Define an input operand:
%operand = pdl.input
// Define an input operand with an expected type:
%type = pdl.type : i32
%attr = pdl.input : %type
Operands: ¶
Operand | Description |
---|---|
type | PDL handle to an mlir::Type |
Results: ¶
Result | Description |
---|---|
val | PDL handle for an mlir::Value |
pdl.operation
(::mlir::pdl::OperationOp) ¶
Define an operation within a pattern
pdl.operation
operations define operation nodes within a pattern. Within
a match sequence, i.e. when directly nested within a pdl.pattern
, these
operations correspond to input operations, or those that already existing
within the MLIR module. Inside of a pdl.rewrite
, these operations
correspond to operations that should be created as part of the replacement
sequence.
pdl.operation
s are composed of a name, and a set of attribute, operand,
and result type values, that map to what those that would be on a
constructed instance of that operation. The results of a pdl.operation
are
a handle to the operation itself, and a handle to each of the operation
result values.
When used within a matching context, the name of the operation may be omitted.
When used within a rewriting context, i.e. when defined within a
pdl.rewrite
, all of the result types must be “inferable”. This means that
the type must be attributable to either a constant type value or the result
type of another entity, such as an attribute, the result of a
createNative
, or the result type of another operation. If the result type
value does not meet any of these criteria, the operation must provide the
InferTypeOpInterface
to ensure that the result types can be inferred.
Example:
// Define an instance of a `foo.op` operation.
%op, %results:4 = pdl.operation "foo.op"(%arg0, %arg1) {"attrA" = %attr0} -> %type, %type, %type, %type
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
attributeNames | ::mlir::ArrayAttr | string array attribute |
Operands: ¶
Operand | Description |
---|---|
operands | PDL handle for an mlir::Value |
attributes | PDL handle to an mlir::Attribute |
types | PDL handle to an mlir::Type |
Results: ¶
Result | Description |
---|---|
op | PDL handle to an mlir::Operation * |
results | PDL handle for an mlir::Value |
pdl.pattern
(::mlir::pdl::PatternOp) ¶
Define a rewrite pattern
Syntax:
operation ::= `pdl.pattern` ($sym_name^)? `:` `benefit` `(` $benefit `)`
(`,` `root` `(` $rootKind^ `)`)? attr-dict-with-keyword $body
pdl.pattern
operations provide a transformable representation for a
RewritePattern
. The attributes on this operation correspond to the various
metadata on a RewritePattern
, such as the benefit. The match section of
the pattern is specified within the region body, with the rewrite provided
by a terminating pdl.rewrite
.
Example:
// Provide a pattern matching "foo.op" that replaces the root with its
// input.
pdl.pattern : benefit(1) {
%resultType = pdl.type
%inputOperand = pdl.input
%root, %results = pdl.operation "foo.op"(%inputOperand) -> (%resultType)
pdl.rewrite %root {
pdl.replace %root with (%inputOperand)
}
}
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
rootKind | ::mlir::StringAttr | string attribute |
benefit | ::mlir::IntegerAttr | 16-bit signless integer attribute whose value is non-negative |
sym_name | ::mlir::StringAttr | string attribute |
pdl.replace
(::mlir::pdl::ReplaceOp) ¶
Mark an input operation as replaced
Syntax:
operation ::= `pdl.replace` $operation `with` (`(` $replValues^ `)`)? ($replOperation^)? attr-dict
pdl.replace
operations are used within pdl.rewrite
regions to specify
that an input operation should be marked as replaced. The semantics of this
operation correspond with the replaceOp
method on a PatternRewriter
. The
set of replacement values can be either:
- a single
Operation
(replOperation
should be populated)- The operation will be replaced with the results of this operation.
- a set of
Value
s (replValues
should be populated)- The operation will be replaced with these values.
Example:
// Replace root node with 2 values:
pdl.replace %root with (%val0, %val1)
// Replace root with another operation:
pdl.replace %root with %otherOp
Operands: ¶
Operand | Description |
---|---|
operation | PDL handle to an mlir::Operation * |
replOperation | PDL handle to an mlir::Operation * |
replValues | PDL handle for an mlir::Value |
pdl.rewrite_end
(::mlir::pdl::RewriteEndOp) ¶
Implicit terminator of a pdl.rewrite
region
Syntax:
operation ::= `pdl.rewrite_end` attr-dict
pdl.rewrite_end
operations terminate the region of a pdl.rewrite
.
pdl.rewrite
(::mlir::pdl::RewriteOp) ¶
Specify the rewrite of a matched pattern
Syntax:
operation ::= `pdl.rewrite` $root (`with` $name^ ($externalConstParams^)?
(`(` $externalArgs^ `:` type($externalArgs) `)`)?)?
($body^)?
attr-dict-with-keyword
pdl.rewrite
operations terminate the region of a pdl.pattern
and specify
the rewrite of a pdl.pattern
, on the specified root operation. The
rewrite is specified either via a string name (name
) to an external
rewrite function, or via the region body. The rewrite region, if specified,
must contain a single block and terminate via the pdl.rewrite_end
operation. If the rewrite is external, it also takes a set of constant
parameters and a set of additional positional values defined within the
matcher as arguments.
Example:
// Specify an external rewrite function:
pdl.rewrite %root with "myExternalRewriter"(%value : !pdl.value)
// Specify the rewrite inline using PDL:
pdl.rewrite %root {
%op = pdl.operation "foo.op"(%arg0, %arg1)
pdl.replace %root with %op
}
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
name | ::mlir::StringAttr | string attribute |
externalConstParams | ::mlir::ArrayAttr | array attribute |
Operands: ¶
Operand | Description |
---|---|
root | PDL handle to an mlir::Operation * |
externalArgs | Positional Value |
pdl.type
(::mlir::pdl::TypeOp) ¶
Define a type handle within a pattern
Syntax:
operation ::= `pdl.type` attr-dict (`:` $type^)?
pdl.type
operations capture result type constraints of an Attributes
,
Values
, and Operations
. Instances of this operation define, and
partially constrain, results types of a given entity. A pdl.type
may
partially constrain the result by specifying a constant Type
.
Example:
// Define a type:
%attr = pdl.type
// Define a type with a constant value:
%attr = pdl.type : i32
Attributes: ¶
Attribute | MLIR Type | Description |
---|---|---|
type | ::mlir::TypeAttr | any type attribute |
Results: ¶
Result | Description |
---|---|
result | PDL handle to an mlir::Type |
Type definition ¶
PDL_Attribute
(AttributeType) ¶
PDL handle to an mlir::Attribute
This type represents a handle to an instance of an mlir::Attribute
, bound
to a value that is usable within a PDL pattern or rewrite.
PDL_Operation
(OperationType) ¶
PDL handle to an mlir::Operation *
This type represents a handle to an instance of an mlir::Operation *
,
bound to a value that is usable within a PDL pattern or rewrite.
PDL_Type
(TypeType) ¶
PDL handle to an mlir::Type
This type represents a handle to an instance of an mlir::Type
, bound to a
value that is usable within a PDL pattern or rewrite.
PDL_Value
(ValueType) ¶
PDL handle for an mlir::Value
This type represents a handle to an instance of an mlir::Value
, bound to a
value that is usable within a PDL pattern or rewrite.