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

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

#### Operands: ¶

OperandDescription
argsPositional 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: ¶

AttributeMLIR TypeDescription
value::mlir::Attributeany attribute

#### Operands: ¶

OperandDescription
typePDL handle to an mlir::Type

#### Results: ¶

ResultDescription
attrPDL 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: ¶ AttributeMLIR TypeDescription name::mlir::StringAttrstring attribute constParams::mlir::ArrayAttrarray attribute #### Operands: ¶ OperandDescription argsPositional Value #### Results: ¶ ResultDescription resultPositional 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: ¶

OperandDescription
operationPDL 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: ¶ OperandDescription typePDL handle to an mlir::Type #### Results: ¶ ResultDescription valPDL 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.operations 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: ¶ AttributeMLIR TypeDescription name::mlir::StringAttrstring attribute attributeNames::mlir::ArrayAttrstring array attribute #### Operands: ¶ OperandDescription operandsPDL handle for an mlir::Value attributesPDL handle to an mlir::Attribute typesPDL handle to an mlir::Type #### Results: ¶ ResultDescription opPDL handle to an mlir::Operation * resultsPDL 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: ¶ AttributeMLIR TypeDescription rootKind::mlir::StringAttrstring attribute benefit::mlir::IntegerAttr16-bit signless integer attribute whose value is non-negative sym_name::mlir::StringAttrstring 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 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)

// Replace root with another operation:
pdl.replace %root with %otherOp


#### Operands: ¶

OperandDescription
operationPDL handle to an mlir::Operation *
replOperationPDL handle to an mlir::Operation *
replValuesPDL 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: ¶

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

#### Operands: ¶

OperandDescription
rootPDL handle to an mlir::Operation *
externalArgsPositional 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: ¶

AttributeMLIR TypeDescription
type::mlir::TypeAttrany type attribute

#### Results: ¶

ResultDescription
resultPDL 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.