# MLIR

Multi-Level IR Compiler Framework

# '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.operand operations.
// Result types are constrainted via pdl.type operations.

%resultType = pdl.type
%inputOperand = pdl.operand
%root = 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 a range of a given sub-type ¶

This type represents a range of instances of the given PDL element type, i.e. Attribute, Operation, Type, or Value.

### 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_native_constraint (::mlir::pdl::ApplyNativeConstraintOp) ¶

Apply a native constraint to a set of provided entities

Syntax:

operation ::= pdl.apply_native_constraint $name ($constParams^)? ( $args : type($args) ) attr-dict


pdl.apply_native_constraint operations apply a native C++ 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_native_constraint "myConstraint"[42, "abc", i32](%input, %attr, %op : !pdl.value, !pdl.attribute, !pdl.operation)


#### Attributes: ¶

AttributeMLIR TypeDescription
name::mlir::StringAttrstring attribute
constParams::mlir::ArrayAttrarray attribute

#### Operands: ¶

OperandDescription
argspdl type

### pdl.apply_native_rewrite (::mlir::pdl::ApplyNativeRewriteOp) ¶

Apply a native rewrite method inside of pdl.rewrite region

Syntax:

operation ::= pdl.apply_native_rewrite $name ($constParams^)? (( $args^ : type($args) ))? : type($results) attr-dict  pdl.apply_native_rewrite operations apply a native C++ function, that has been registered externally with the consumer of PDL, to perform a rewrite and optionally return a number of values. The native function may accept any number of arguments and constant attribute parameters. This operation is used within a pdl.rewrite region to enable the interleaving of native rewrite methods with other pdl constructs. Example: // Apply a native rewrite method that returns an attribute. %ret = pdl.apply_native_rewrite "myNativeFunc"[42, "gt"](%arg0, %arg1) : !pdl.attribute  // The native rewrite as defined in C++: static void myNativeFunc(ArrayRef<PDLValue> args, ArrayAttr constantParams, PatternRewriter &rewriter, PDLResultList &results) { Value arg0 = args[0].cast<Value>(); Value arg1 = args[1].cast<Value>(); IntegerAttr param0 = constantParams[0].cast<IntegerAttr>(); StringAttr param1 = constantParams[1].cast<StringAttr>(); // Just push back the first param attribute. results.push_back(param0); } void registerNativeRewrite(PDLPatternModule &pdlModule) { pdlModule.registerRewriteFunction("myNativeFunc", myNativeFunc); }  #### Attributes: ¶ AttributeMLIR TypeDescription name::mlir::StringAttrstring attribute constParams::mlir::ArrayAttrarray attribute #### Operands: ¶ OperandDescription argspdl type #### Results: ¶ ResultDescription resultspdl type ### 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: ¶ AttributeMLIR TypeDescription value::mlir::Attributeany attribute #### Operands: ¶ OperandDescription typePDL handle to an mlir::Type #### Results: ¶ ResultDescription attrPDL handle to an mlir::Attribute ### 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: ¶

OperandDescription
operationPDL handle to an mlir::Operation *

### pdl.operand (::mlir::pdl::OperandOp) ¶

Define an external input operand in a pattern

Syntax:

operation ::= pdl.operand (: $type^)? attr-dict  pdl.operand operations capture external operand edges into an operation node that originate from operations or block arguments not otherwise specified within the pattern (i.e. via pdl.result or pdl.results). These operations define individual operands of a given operation. A pdl.operand may partially constrain an operand by specifying an expected value type (via a pdl.type operation). Example: // Define an external operand: %operand = pdl.operand // Define an external operand with an expected type: %type = pdl.type : i32 %operand = pdl.operand : %type  #### Operands: ¶ OperandDescription typePDL handle to an mlir::Type #### Results: ¶ ResultDescription valPDL handle for an mlir::Value ### pdl.operands (::mlir::pdl::OperandsOp) ¶ Define a range of input operands in a pattern Syntax: operation ::= pdl.operands (:$type^)? attr-dict


pdl.operands operations capture external operand range edges into an operation node that originate from operations or block arguments not otherwise specified within the pattern (i.e. via pdl.result or pdl.results). These operations define groups of input operands into a given operation. A pdl.operands may partially constrain a set of input operands by specifying expected value types (via pdl.types operations).

Example:

// Define a range of input operands:
%operands = pdl.operands

// Define a range of input operands with expected types:
%types = pdl.types : [i32, i64, i32]
%typed_operands = pdl.operands : %types


#### Operands: ¶

OperandDescription
typerange of PDL handle to an mlir::Type values

#### Results: ¶

ResultDescription
valrange of PDL handle for an mlir::Value values

### pdl.operation (::mlir::pdl::OperationOp) ¶

Define an operation within a pattern

Syntax:

($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 Values (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 : !pdl.value, !pdl.value) // Replace root node with a range of values: pdl.replace %root with (%vals : !pdl.range<value>) // Replace root with another operation: pdl.replace %root with %otherOp  #### Operands: ¶ OperandDescription operationPDL handle to an mlir::Operation * replOperationPDL handle to an mlir::Operation * replValuessingle element or range of PDL handle for an mlir::Value ### pdl.result (::mlir::pdl::ResultOp) ¶ Extract a result from an operation Syntax: operation ::= pdl.result$index of $parent attr-dict  pdl.result operations extract result edges from an operation node within a pattern or rewrite region. The provided index is zero-based, and represents the concrete result to extract, i.e. this is not the result index as defined by the ODS definition of the operation. Example: // Extract a result: %operation = pdl.operation ... %pdl_result = pdl.result 1 of %operation // Imagine the following IR being matched: %result_0, %result_1 = foo.op ... // If the example pattern snippet above were matching against foo.op in // the IR snippet, %pdl_result would correspond to %result_1.  #### Attributes: ¶ AttributeMLIR TypeDescription index::mlir::IntegerAttr32-bit signless integer attribute #### Operands: ¶ OperandDescription parentPDL handle to an mlir::Operation * #### Results: ¶ ResultDescription valPDL handle for an mlir::Value ### pdl.results (::mlir::pdl::ResultsOp) ¶ Extract a result group from an operation Syntax: operation ::= pdl.results ($index^)? of $parent custom<ResultsValueType>(ref($index), type($val)) attr-dict  pdl.results operations extract a result group from an operation within a pattern or rewrite region. If an index is provided, this operation extracts a result group as defined by the ODS definition of the operation. In this case the result of this operation may be either a single pdl.value or a pdl.range<value>, depending on the constraint of the result in ODS. If no index is provided, this operation extracts the full result range of the operation. Example: // Extract all of the results of an operation: %operation = pdl.operation ... %results = pdl.results of %operation // Extract the results in the first result group of an operation, which is // variadic: %operation = pdl.operation ... %results = pdl.results 0 of %operation -> !pdl.range<value> // Extract the results in the second result group of an operation, which is // not variadic: %operation = pdl.operation ... %results = pdl.results 1 of %operation -> !pdl.value  #### Attributes: ¶ AttributeMLIR TypeDescription index::mlir::IntegerAttr32-bit signless integer attribute #### Operands: ¶ OperandDescription parentPDL handle to an mlir::Operation * #### Results: ¶ ResultDescription valsingle element or range of 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 main 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. If the rewrite is external, the root operation is passed to the native function as the first argument. 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: ¶ AttributeMLIR TypeDescription name::mlir::StringAttrstring attribute externalConstParams::mlir::ArrayAttrarray attribute #### Operands: ¶ OperandDescription rootPDL handle to an mlir::Operation * externalArgspdl type ### 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 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:
%type = pdl.type

// Define a type with a constant value:
%type = pdl.type : i32


#### Attributes: ¶

AttributeMLIR TypeDescription
type::mlir::TypeAttrany type attribute

#### Results: ¶

ResultDescription
resultPDL handle to an mlir::Type

### pdl.types (::mlir::pdl::TypesOp) ¶

Define a range of type handles within a pattern

Syntax:

operation ::= pdl.types attr-dict (: \$types^)?


pdl.types operations capture result type constraints of Values, and Operations. Instances of this operation define results types of a given entity. A pdl.types may partially constrain the results by specifying an array of Types.

Example:

// Define a range of types:
%types = pdl.types

// Define a range of types with a range of constant values:
%types = pdl.types : [i32, i64, i32]


#### Attributes: ¶

AttributeMLIR TypeDescription
types::mlir::ArrayAttrtype array attribute

#### Results: ¶

ResultDescription
resultrange of PDL handle to an mlir::Type values

## Type definition ¶

### 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.

### 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.

### RangeType ¶

PDL handle to a range of a given sub-type

This type represents a range of instances of the given PDL element type, i.e. Attribute, Operation, Type, or Value.

#### Parameters: ¶

ParameterC++ typeDescription
elementTypeType

### 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.

### 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.