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.

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.

‘pdl_interp’ Dialect

Interpreted pattern execution dialect The PDL Interpreter dialect provides a lower level abstraction compared to the PDL dialect, and is targeted towards low level optimization and interpreter code generation. The dialect operations encapsulates low-level pattern match and rewrite “primitives”, such as navigating the IR (Operation::getOperand), creating new operations (OpBuilder::create), etc. Many of the operations within this dialect also fuse branching control flow with some form of a predicate comparison operation. This type of fusion reduces the amount of work that an interpreter must do when executing.

Operation definition 

pdl_interp.apply_constraint (::mlir::pdl_interp::ApplyConstraintOp) 

Apply a constraint to a set of positional values

Syntax:

operation ::= `pdl_interp.apply_constraint` $name ($constParams^)? `(` $args `:` type($args) `)` attr-dict `->`
              successors

pdl_interp.apply_constraint operations apply a generic constraint, that has been registered with the interpreter, with a given set of positional values. The constraint may have any number of constant parameters. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

// Apply `myConstraint` to the entities defined by `input`, `attr`, and
// `op`.
pdl_interp.apply_constraint "myConstraint"[42, "abc", i32](%input, %attr, %op : !pdl.value, !pdl.attribute, !pdl.operation) -> ^matchDest, ^failureDest

Attributes: 

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

Operands: 

OperandDescription
argsPositional Value

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.apply_rewrite (::mlir::pdl_interp::ApplyRewriteOp) 

Invoke and apply an externally registered rewrite method

Syntax:

operation ::= `pdl_interp.apply_rewrite` $name ($constParams^)? (`(` $args^ `:` type($args) `)`)? `on` $root
              attr-dict

pdl_interp.apply_rewrite operations invoke an external rewriter that has been registered with the interpreter to perform the rewrite after a successful match. The rewrite is passed the root operation being matched, a set of additional positional arguments generated within the matcher, and a set of constant parameters.

Example:

// Rewriter operating solely on the root operation.
pdl_interp.apply_rewrite "rewriter" on %root

// Rewriter operating on the root operation along with additional arguments
// from the matcher.
pdl_interp.apply_rewrite "rewriter"(%value : !pdl.value) on %root

// Rewriter operating on the root operation along with additional arguments
// and constant parameters.
pdl_interp.apply_rewrite "rewriter"[42](%value : !pdl.value) on %root

Attributes: 

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

Operands: 

OperandDescription
rootPDL handle to an mlir::Operation *
argsPositional Value

pdl_interp.are_equal (::mlir::pdl_interp::AreEqualOp) 

Check if two positional values are equivalent

Syntax:

operation ::= `pdl_interp.are_equal` operands `:` type($lhs) attr-dict `->` successors

pdl_interp.are_equal operations compare two positional values for equality. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

pdl_interp.are_equal %result1, %result2 : !pdl.value -> ^matchDest, ^failureDest

Operands: 

OperandDescription
lhsPositional Value
rhsPositional Value

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.branch (::mlir::pdl_interp::BranchOp) 

General branch operation

Syntax:

operation ::= `pdl_interp.branch` $dest attr-dict

pdl_interp.branch operations expose general branch functionality to the interpreter, and are generally used to branch from one pattern match sequence to another.

Example:

pdl_interp.branch ^dest

Successors: 

SuccessorDescription
destany successor

pdl_interp.check_attribute (::mlir::pdl_interp::CheckAttributeOp) 

Check the value of an Attribute

Syntax:

operation ::= `pdl_interp.check_attribute` $attribute `is` $constantValue attr-dict `->` successors

pdl_interp.check_attribute operations compare the value of a given attribute with a constant value. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

pdl_interp.check_attribute %attr is 10 -> ^matchDest, ^failureDest

Attributes: 

AttributeMLIR TypeDescription
constantValue::mlir::Attributeany attribute

Operands: 

OperandDescription
attributePDL handle to an mlir::Attribute

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.check_operand_count (::mlir::pdl_interp::CheckOperandCountOp) 

Check the number of operands of an Operation

Syntax:

operation ::= `pdl_interp.check_operand_count` `of` $operation `is` $count attr-dict `->` successors

pdl_interp.check_operand_count operations compare the number of operands of a given operation value with a constant. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

pdl_interp.check_operand_count of %op is 2 -> ^matchDest, ^failureDest

Attributes: 

AttributeMLIR TypeDescription
count::mlir::IntegerAttr32-bit signless integer attribute whose value is non-negative

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.check_operation_name (::mlir::pdl_interp::CheckOperationNameOp) 

Check the OperationName of an Operation

Syntax:

operation ::= `pdl_interp.check_operation_name` `of` $operation `is` $name attr-dict `->` successors

pdl_interp.check_operation_name operations compare the name of a given operation with a known name. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

pdl_interp.check_operation_name of %op is "foo.op" -> ^matchDest, ^failureDest

Attributes: 

AttributeMLIR TypeDescription
name::mlir::StringAttrstring attribute

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.check_result_count (::mlir::pdl_interp::CheckResultCountOp) 

Check the number of results of an Operation

Syntax:

operation ::= `pdl_interp.check_result_count` `of` $operation `is` $count attr-dict `->` successors

pdl_interp.check_result_count operations compare the number of results of a given operation value with a constant. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

pdl_interp.check_result_count of %op is 0 -> ^matchDest, ^failureDest

Attributes: 

AttributeMLIR TypeDescription
count::mlir::IntegerAttr32-bit signless integer attribute whose value is non-negative

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.check_type (::mlir::pdl_interp::CheckTypeOp) 

Compare a type to a known value

Syntax:

operation ::= `pdl_interp.check_type` $value `is` $type attr-dict `->` successors

pdl_interp.check_type operations compare a type with a statically known type. On success, this operation branches to the true destination, otherwise the false destination is taken.

Example:

pdl_interp.check_type %type is i32 -> ^matchDest, ^failureDest

Attributes: 

AttributeMLIR TypeDescription
type::mlir::TypeAttrany type attribute

Operands: 

OperandDescription
valuePDL handle to an mlir::Type

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.create_attribute (::mlir::pdl_interp::CreateAttributeOp) 

Create an interpreter handle to a constant Attribute

Syntax:

operation ::= `pdl_interp.create_attribute` $value attr-dict

pdl_interp.create_attribute operations generate a handle within the interpreter for a specific constant attribute value.

Example:

%attr = pdl_interp.create_attribute 10 : i64

Attributes: 

AttributeMLIR TypeDescription
value::mlir::Attributeany attribute

Results: 

ResultDescription
attributePDL handle to an mlir::Attribute

pdl_interp.create_native (::mlir::pdl_interp::CreateNativeOp) 

Call a native creation method to construct an Attribute, Operation, Type, or Value

Syntax:

operation ::= `pdl_interp.create_native` $name ($constParams^)? (`(` $args^ `:` type($args) `)`)? `:` type($result)
              attr-dict

pdl_interp.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_interp.create_native "myNativeFunc"[42, "gt"](%arg0, %arg1 : !pdl.value, !pdl.value) : !pdl.attribute

Attributes: 

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

Operands: 

OperandDescription
argsPositional Value

Results: 

ResultDescription
resultPositional Value

pdl_interp.create_operation (::mlir::pdl_interp::CreateOperationOp) 

Create an instance of a specific Operation

pdl_interp.create_operation operations create an Operation instance with the specified attributes, operands, and result types.

Example:

// Create an instance of a `foo.op` operation.
%op = pdl_interp.create_operation "foo.op"(%arg0) {"attrA" = %attr0} -> %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
operationPDL handle to an mlir::Operation *

pdl_interp.create_type (::mlir::pdl_interp::CreateTypeOp) 

Create an interpreter handle to a constant Type

Syntax:

operation ::= `pdl_interp.create_type` $value attr-dict

pdl_interp.create_type operations generate a handle within the interpreter for a specific constant type value.

Example:

pdl_interp.create_type i64

Attributes: 

AttributeMLIR TypeDescription
value::mlir::TypeAttrany type attribute

Results: 

ResultDescription
resultPDL handle to an mlir::Type

pdl_interp.erase (::mlir::pdl_interp::EraseOp) 

Mark an operation as erased

Syntax:

operation ::= `pdl_interp.erase` $operation attr-dict

pdl.erase operations are used to specify that an operation should be marked as erased. The semantics of this operation correspond with the eraseOp method on a PatternRewriter.

Example:

pdl_interp.erase %root

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

pdl_interp.finalize (::mlir::pdl_interp::FinalizeOp) 

Finalize a pattern match or rewrite sequence

Syntax:

operation ::= `pdl_interp.finalize` attr-dict

pdl_interp.finalize is used to denote the termination of a match or rewrite sequence.

Example:

pdl_interp.finalize

pdl_interp.get_attribute (::mlir::pdl_interp::GetAttributeOp) 

Get a specified attribute value from an Operation

Syntax:

operation ::= `pdl_interp.get_attribute` $name `of` $operation attr-dict

pdl_interp.get_attribute operations try to get a specific attribute from an operation. If the operation does not have that attribute, a null value is returned.

Example:

%attr = pdl_interp.get_attribute "attr" of %op

Attributes: 

AttributeMLIR TypeDescription
name::mlir::StringAttrstring attribute

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Results: 

ResultDescription
attributePDL handle to an mlir::Attribute

pdl_interp.get_attribute_type (::mlir::pdl_interp::GetAttributeTypeOp) 

Get the result type of a specified Attribute

Syntax:

operation ::= `pdl_interp.get_attribute_type` `of` $value attr-dict

pdl_interp.get_attribute_type operations get the resulting type of a specific attribute.

Example:

%type = pdl_interp.get_attribute_type of %attr

Operands: 

OperandDescription
valuePDL handle to an mlir::Attribute

Results: 

ResultDescription
resultPDL handle to an mlir::Type

pdl_interp.get_defining_op (::mlir::pdl_interp::GetDefiningOpOp) 

Get the defining operation of a Value

Syntax:

operation ::= `pdl_interp.get_defining_op` `of` $value attr-dict

pdl_interp.get_defining_op operations try to get the defining operation of a specific value. If the value is not an operation result, null is returned.

Example:

%op = pdl_interp.get_defining_op of %value

Operands: 

OperandDescription
valuePDL handle for an mlir::Value

Results: 

ResultDescription
operationPDL handle to an mlir::Operation *

pdl_interp.get_operand (::mlir::pdl_interp::GetOperandOp) 

Get a specified operand from an Operation

Syntax:

operation ::= `pdl_interp.get_operand` $index `of` $operation attr-dict

pdl_interp.get_operand operations try to get a specific operand from an operation If the operation does not have an operand for the given index, a null value is returned.

Example:

%operand = pdl_interp.get_operand 1 of %op

Attributes: 

AttributeMLIR TypeDescription
index::mlir::IntegerAttr32-bit signless integer attribute whose value is non-negative

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Results: 

ResultDescription
valuePDL handle for an mlir::Value

pdl_interp.get_result (::mlir::pdl_interp::GetResultOp) 

Get a specified result from an Operation

Syntax:

operation ::= `pdl_interp.get_result` $index `of` $operation attr-dict

pdl_interp.get_result operations try to get a specific result from an operation. If the operation does not have a result for the given index, a null value is returned.

Example:

%result = pdl_interp.get_result 1 of %op

Attributes: 

AttributeMLIR TypeDescription
index::mlir::IntegerAttr32-bit signless integer attribute whose value is non-negative

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Results: 

ResultDescription
valuePDL handle for an mlir::Value

pdl_interp.get_value_type (::mlir::pdl_interp::GetValueTypeOp) 

Get the result type of a specified Value

Syntax:

operation ::= `pdl_interp.get_value_type` `of` $value attr-dict

pdl_interp.get_value_type operations get the resulting type of a specific value.

Example:

%type = pdl_interp.get_value_type of %value

Operands: 

OperandDescription
valuePDL handle for an mlir::Value

Results: 

ResultDescription
resultPDL handle to an mlir::Type

pdl_interp.inferred_type (::mlir::pdl_interp::InferredTypeOp) 

Generate a handle to a Type that is “inferred”

Syntax:

operation ::= `pdl_interp.inferred_type` attr-dict

pdl_interp.inferred_type operations generate a handle to a type that should be inferred. This signals to other operations, such as pdl_interp.create_operation, that this type should be inferred.

Example:

pdl_interp.inferred_type

Results: 

ResultDescription
typePDL handle to an mlir::Type

pdl_interp.is_not_null (::mlir::pdl_interp::IsNotNullOp) 

Check if a positional value is non-null

Syntax:

operation ::= `pdl_interp.is_not_null` $value `:` type($value) attr-dict `->` successors

pdl_interp.is_not_null operations check that a positional value exists. On success, this operation branches to the true destination. Otherwise, the false destination is taken.

Example:

pdl_interp.is_not_null %value : !pdl.value -> ^matchDest, ^failureDest

Operands: 

OperandDescription
valuePositional Value

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

pdl_interp.record_match (::mlir::pdl_interp::RecordMatchOp) 

Record the metadata for a successful pattern match

Syntax:

operation ::= `pdl_interp.record_match` $rewriter (`(` $inputs^ `:` type($inputs) `)`)? `:`
              `benefit` `(` $benefit `)` `,`
              (`generatedOps` `(` $generatedOps^ `)` `,`)?
              `loc` `(` `[` $matchedOps `]` `)`
              (`,` `root` `(` $rootKind^ `)`)? attr-dict `->` $dest

pdl_interp.record_match operations record a successful pattern match with the interpreter and branch to the next part of the matcher. The metadata recorded by these operations correspond to a specific pdl.pattern, as well as what values were used during that match that should be propagated to the rewriter.

Example:

pdl_interp.record_match @rewriters::myRewriter(%root : !pdl.operation) : benefit(1), loc([%root, %op1]), root("foo.op") -> ^nextDest

Attributes: 

AttributeMLIR TypeDescription
rewriter::mlir::SymbolRefAttrsymbol reference attribute
rootKind::mlir::StringAttrstring attribute
generatedOps::mlir::ArrayAttrstring array attribute
benefit::mlir::IntegerAttr16-bit signless integer attribute whose value is non-negative

Operands: 

OperandDescription
inputsPositional Value
matchedOpsPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
destany successor

pdl_interp.replace (::mlir::pdl_interp::ReplaceOp) 

Mark an operation as replaced

Syntax:

operation ::= `pdl_interp.replace` $operation `with` `(` $replValues `)` attr-dict

pdl_interp.replaced operations are used to specify that an operation should be marked as replaced. The semantics of this operation correspond with the replaceOp method on a PatternRewriter. The set of replacement values must match the number of results specified by the operation.

Example:

// Replace root node with 2 values:
pdl_interp.replace %root with (%val0, %val1)

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *
replValuesPDL handle for an mlir::Value

pdl_interp.switch_attribute (::mlir::pdl_interp::SwitchAttributeOp) 

Switch on the value of an Attribute

Syntax:

operation ::= `pdl_interp.switch_attribute` $attribute `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest

pdl_interp.switch_attribute operations compare the value of a given attribute with a set of constant attributes. If the value matches one of the provided case values the destination for that case value is taken, otherwise the default destination is taken.

Example:

pdl_interp.switch_attribute %attr to [10, true](^10Dest, ^trueDest) -> ^defaultDest

Attributes: 

AttributeMLIR TypeDescription
caseValues::mlir::ArrayAttrarray attribute

Operands: 

OperandDescription
attributePDL handle to an mlir::Attribute

Successors: 

SuccessorDescription
defaultDestany successor
casesany successor

pdl_interp.switch_operand_count (::mlir::pdl_interp::SwitchOperandCountOp) 

Switch on the operand count of an Operation

Syntax:

operation ::= `pdl_interp.switch_operand_count` `of` $operation `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest

pdl_interp.switch_operand_count operations compare the operand count of a given operation with a set of potential counts. If the value matches one of the provided case values the destination for that case value is taken, otherwise the default destination is taken.

Example:

pdl_interp.switch_operand_count of %op to [10, 2] -> ^10Dest, ^2Dest, ^defaultDest

Attributes: 

AttributeMLIR TypeDescription
caseValues::mlir::DenseIntElementsAttr32-bit signless integer elements attribute

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
defaultDestany successor
casesany successor

pdl_interp.switch_operation_name (::mlir::pdl_interp::SwitchOperationNameOp) 

Switch on the OperationName of an Operation

Syntax:

operation ::= `pdl_interp.switch_operation_name` `of` $operation `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest

pdl_interp.switch_operation_name operations compare the name of a given operation with a set of known names. If the value matches one of the provided case values the destination for that case value is taken, otherwise the default destination is taken.

Example:

pdl_interp.switch_operation_name of %op to ["foo.op", "bar.op"](^fooDest, ^barDest) -> ^defaultDest

Attributes: 

AttributeMLIR TypeDescription
caseValues::mlir::ArrayAttrstring array attribute

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
defaultDestany successor
casesany successor

pdl_interp.switch_result_count (::mlir::pdl_interp::SwitchResultCountOp) 

Switch on the result count of an Operation

Syntax:

operation ::= `pdl_interp.switch_result_count` `of` $operation `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest

pdl_interp.switch_result_count operations compare the result count of a given operation with a set of potential counts. If the value matches one of the provided case values the destination for that case value is taken, otherwise the default destination is taken.

Example:

pdl_interp.switch_result_count of %op to [0, 2](^0Dest, ^2Dest) -> ^defaultDest

Attributes: 

AttributeMLIR TypeDescription
caseValues::mlir::DenseIntElementsAttr32-bit signless integer elements attribute

Operands: 

OperandDescription
operationPDL handle to an mlir::Operation *

Successors: 

SuccessorDescription
defaultDestany successor
casesany successor

pdl_interp.switch_type (::mlir::pdl_interp::SwitchTypeOp) 

Switch on a Type value

Syntax:

operation ::= `pdl_interp.switch_type` $value `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest

pdl_interp.switch_type operations compare a type with a set of statically known types. If the value matches one of the provided case values the destination for that case value is taken, otherwise the default destination is taken.

Example:

pdl_interp.switch_type %type to [i32, i64] -> ^i32Dest, ^i64Dest, ^defaultDest

Attributes: 

AttributeMLIR TypeDescription
caseValues::mlir::ArrayAttrtype array attribute

Operands: 

OperandDescription
valuePDL handle to an mlir::Type

Successors: 

SuccessorDescription
defaultDestany successor
casesany successor