724 lines
27 KiB
TableGen
724 lines
27 KiB
TableGen
//===- PDLOps.td - Pattern descriptor operations -----------*- tablegen -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file declares the Pattern Descriptor Language dialect operations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef MLIR_DIALECT_PDL_IR_PDLOPS
|
|
#define MLIR_DIALECT_PDL_IR_PDLOPS
|
|
|
|
include "mlir/Dialect/PDL/IR/PDLTypes.td"
|
|
include "mlir/IR/OpAsmInterface.td"
|
|
include "mlir/IR/SymbolInterfaces.td"
|
|
include "mlir/Interfaces/SideEffectInterfaces.td"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PDL Ops
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
class PDL_Op<string mnemonic, list<Trait> traits = []>
|
|
: Op<PDL_Dialect, mnemonic, traits>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::ApplyNativeConstraintOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_ApplyNativeConstraintOp
|
|
: PDL_Op<"apply_native_constraint", [HasParent<"pdl::PatternOp">]> {
|
|
let summary = "Apply a native constraint to a set of provided entities";
|
|
let description = [{
|
|
`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 and optionally return a number of values.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Apply `myConstraint` to the entities defined by `input`, `attr`, and `op`.
|
|
pdl.apply_native_constraint "myConstraint"(%input, %attr, %op : !pdl.value, !pdl.attribute, !pdl.operation)
|
|
// Apply constraint `with_result` to `root`. This constraint returns an attribute.
|
|
%attr = pdl.apply_native_constraint "with_result"(%root : !pdl.operation) : !pdl.attribute
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins StrAttr:$name,
|
|
Variadic<PDL_AnyType>:$args,
|
|
DefaultValuedAttr<BoolAttr, "false">:$isNegated);
|
|
let results = (outs Variadic<PDL_AnyType>:$results);
|
|
let assemblyFormat = [{
|
|
$name `(` $args `:` type($args) `)` (`:` type($results)^ )? attr-dict
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::ApplyNativeRewriteOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_ApplyNativeRewriteOp
|
|
: PDL_Op<"apply_native_rewrite", [HasParent<"pdl::RewriteOp">]> {
|
|
let summary = "Apply a native rewrite method inside of pdl.rewrite region";
|
|
let description = [{
|
|
`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. This operation is used within a pdl.rewrite region to enable
|
|
the interleaving of native rewrite methods with other pdl constructs.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Apply a native rewrite method that returns an attribute.
|
|
%ret = pdl.apply_native_rewrite "myNativeFunc"(%arg0, %attr1) : !pdl.attribute
|
|
```
|
|
|
|
```c++
|
|
// The native rewrite as defined in C++:
|
|
static Attribute myNativeFunc(PatternRewriter &rewriter, Value arg0, Attribute arg1) {
|
|
// Just return the second arg.
|
|
return arg1;
|
|
}
|
|
|
|
void registerNativeRewrite(PDLPatternModule &pdlModule) {
|
|
pdlModule.registerRewriteFunction("myNativeFunc", myNativeFunc);
|
|
}
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins StrAttr:$name, Variadic<PDL_AnyType>:$args);
|
|
let results = (outs Variadic<PDL_AnyType>:$results);
|
|
let assemblyFormat = [{
|
|
$name (`(` $args^ `:` type($args) `)`)? (`:` type($results)^)? attr-dict
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::AttributeOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_AttributeOp : PDL_Op<"attribute"> {
|
|
let summary = "Define an input attribute in a pattern";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// 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"
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins Optional<PDL_Type>:$valueType,
|
|
OptionalAttr<AnyAttr>:$value);
|
|
let results = (outs PDL_Attribute:$attr);
|
|
let assemblyFormat = "(`:` $valueType^)? (`=` $value^)? attr-dict-with-keyword";
|
|
|
|
let builders = [
|
|
OpBuilder<(ins CArg<"Value", "Value()">:$type), [{
|
|
build($_builder, $_state, $_builder.getType<AttributeType>(), type,
|
|
Attribute());
|
|
}]>,
|
|
OpBuilder<(ins "Attribute":$attr), [{
|
|
build($_builder, $_state, $_builder.getType<AttributeType>(), Value(), attr);
|
|
}]>,
|
|
];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::EraseOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_EraseOp : PDL_Op<"erase", [HasParent<"pdl::RewriteOp">]> {
|
|
let summary = "Mark an input operation as `erased`";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
pdl.erase %root
|
|
```
|
|
}];
|
|
let arguments = (ins PDL_Operation:$opValue);
|
|
let assemblyFormat = "$opValue attr-dict";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::OperandOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_OperandOp
|
|
: PDL_Op<"operand", [HasParent<"pdl::PatternOp">]> {
|
|
let summary = "Define an external input operand in a pattern";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// Define an external operand:
|
|
%operand = pdl.operand
|
|
|
|
// Define an external operand with an expected type:
|
|
%type = pdl.type : i32
|
|
%operand = pdl.operand : %type
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins Optional<PDL_Type>:$valueType);
|
|
let results = (outs PDL_Value:$value);
|
|
let assemblyFormat = "(`:` $valueType^)? attr-dict";
|
|
|
|
let builders = [
|
|
OpBuilder<(ins), [{
|
|
build($_builder, $_state, $_builder.getType<ValueType>(), Value());
|
|
}]>,
|
|
];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::OperandsOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_OperandsOp
|
|
: PDL_Op<"operands", [HasParent<"pdl::PatternOp">]> {
|
|
let summary = "Define a range of input operands in a pattern";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// 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
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins Optional<PDL_RangeOf<PDL_Type>>:$valueType);
|
|
let results = (outs PDL_RangeOf<PDL_Value>:$value);
|
|
let assemblyFormat = "(`:` $valueType^)? attr-dict";
|
|
|
|
let builders = [
|
|
OpBuilder<(ins), [{
|
|
build($_builder, $_state, RangeType::get($_builder.getType<ValueType>()),
|
|
Value());
|
|
}]>,
|
|
];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::OperationOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_OperationOp : PDL_Op<"operation", [AttrSizedOperandSegments]> {
|
|
let summary = "Define an operation within a pattern";
|
|
let description = [{
|
|
`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. Handles to the results of the operation
|
|
can be extracted via `pdl.result`.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Define an instance of a `foo.op` operation.
|
|
%op = pdl.operation "foo.op"(%arg0, %arg1 : !pdl.value, !pdl.value)
|
|
{"attrA" = %attr0} -> (%type, %type : !pdl.type, !pdl.type)
|
|
```
|
|
|
|
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
|
|
`apply_native_rewrite`, or the result type of another operation. If the
|
|
result type value does not meet any of these criteria, the operation must
|
|
override the `InferTypeOpInterface` to ensure that the result types can be
|
|
inferred.
|
|
|
|
The operands of the operation are interpreted in the following ways:
|
|
|
|
1) A single !pdl.range<value>:
|
|
|
|
In this case, the single range is treated as all of the operands of the
|
|
operation.
|
|
|
|
```mlir
|
|
// Define an instance with single range of operands.
|
|
%op = pdl.operation "func.return"(%allArgs : !pdl.range<value>)
|
|
```
|
|
|
|
2) A variadic number of either !pdl.value or !pdl.range<value>:
|
|
|
|
In this case, the inputs are expected to correspond with the operand groups
|
|
defined on the operation in ODS.
|
|
|
|
```tablgen
|
|
// Given the following operation definition in ODS:
|
|
def MyIndirectCallOp {
|
|
let results = (outs FunctionType:$call, Variadic<AnyType>:$args);
|
|
}
|
|
```
|
|
|
|
```mlir
|
|
// We can match the operands as so:
|
|
%op = pdl.operation "my.indirect_call"(%call, %args : !pdl.value, !pdl.range<value>)
|
|
```
|
|
|
|
The results of the operation are interpreted in the following ways:
|
|
|
|
1) A single !pdl.range<type>:
|
|
|
|
In this case, the single range is treated as all of the result types of the
|
|
operation.
|
|
|
|
```mlir
|
|
// Define an instance with single range of types.
|
|
%allResultTypes = pdl.types
|
|
%op = pdl.operation "builtin.unrealized_conversion_cast" -> (%allResultTypes : !pdl.types)
|
|
```
|
|
|
|
2) A variadic number of either !pdl.type or !pdl.range<type>:
|
|
|
|
In this case, the inputs are expected to correspond with the result groups
|
|
defined on the operation in ODS.
|
|
|
|
```tablgen
|
|
// Given the following operation definition in ODS:
|
|
def MyOp {
|
|
let results = (outs SomeType:$result, Variadic<SomeType>:$otherResults);
|
|
}
|
|
```
|
|
|
|
```mlir
|
|
// We can match the results as so:
|
|
%result = pdl.type
|
|
%otherResults = pdl.types
|
|
%op = pdl.operation "foo.op" -> (%result, %otherResults : !pdl.type, !pdl.range<type>)
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins OptionalAttr<StrAttr>:$opName,
|
|
Variadic<PDL_InstOrRangeOf<PDL_Value>>:$operandValues,
|
|
Variadic<PDL_Attribute>:$attributeValues,
|
|
StrArrayAttr:$attributeValueNames,
|
|
Variadic<PDL_InstOrRangeOf<PDL_Type>>:$typeValues);
|
|
let results = (outs PDL_Operation:$op);
|
|
let assemblyFormat = [{
|
|
($opName^)? (`(` $operandValues^ `:` type($operandValues) `)`)?
|
|
custom<OperationOpAttributes>($attributeValues, $attributeValueNames)
|
|
(`->` `(` $typeValues^ `:` type($typeValues) `)`)? attr-dict
|
|
}];
|
|
|
|
let builders =
|
|
[OpBuilder<(ins CArg<"std::optional<StringRef>", "std::nullopt">:$name,
|
|
CArg<"ValueRange", "{}">:$operandValues,
|
|
CArg<"ArrayRef<StringRef>", "{}">:$attrNames,
|
|
CArg<"ValueRange", "{}">:$attrValues,
|
|
CArg<"ValueRange", "{}">:$resultTypes),
|
|
[{
|
|
auto nameAttr = name ? $_builder.getStringAttr(*name) : StringAttr();
|
|
build($_builder, $_state, $_builder.getType<OperationType>(), nameAttr,
|
|
operandValues, attrValues, $_builder.getStrArrayAttr(attrNames),
|
|
resultTypes);
|
|
}]>,
|
|
];
|
|
let extraClassDeclaration = [{
|
|
/// Returns true if the operation type referenced supports result type
|
|
/// inference.
|
|
bool hasTypeInference();
|
|
|
|
/// Returns true if the operation type referenced might support result type
|
|
/// inference, i.e. it supports type reference or is currently not
|
|
/// registered in the context. Returns false if the root operation name
|
|
/// has not been set.
|
|
bool mightHaveTypeInference();
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::PatternOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_PatternOp : PDL_Op<"pattern", [
|
|
IsolatedFromAbove, SingleBlock, Symbol,
|
|
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getDefaultDialect"]>
|
|
]> {
|
|
let summary = "Define a rewrite pattern";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// Provide a pattern matching "foo.op" that replaces the root with its
|
|
// operand.
|
|
pdl.pattern : benefit(1) {
|
|
%resultType = pdl.type
|
|
%inputOperand = pdl.operand
|
|
%root = pdl.operation "foo.op"(%inputOperand) -> (%resultType)
|
|
pdl.rewrite %root {
|
|
pdl.replace %root with (%inputOperand)
|
|
}
|
|
}
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins ConfinedAttr<I16Attr, [IntNonNegative]>:$benefit,
|
|
OptionalAttr<SymbolNameAttr>:$sym_name);
|
|
let regions = (region SizedRegion<1>:$bodyRegion);
|
|
let assemblyFormat = [{
|
|
($sym_name^)? `:` `benefit` `(` $benefit `)` attr-dict-with-keyword $bodyRegion
|
|
}];
|
|
|
|
let builders = [
|
|
OpBuilder<(ins CArg<"std::optional<uint16_t>", "1">:$benefit,
|
|
CArg<"std::optional<StringRef>", "std::nullopt">:$name)>,
|
|
];
|
|
let extraClassDeclaration = [{
|
|
//===------------------------------------------------------------------===//
|
|
// SymbolOpInterface Methods
|
|
//===------------------------------------------------------------------===//
|
|
|
|
/// A PatternOp may optionally define a symbol.
|
|
bool isOptionalSymbol() { return true; }
|
|
|
|
/// Returns the rewrite operation of this pattern.
|
|
RewriteOp getRewriter();
|
|
}];
|
|
let hasRegionVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::RangeOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_RangeOp : PDL_Op<"range", [Pure, HasParent<"pdl::RewriteOp">]> {
|
|
let summary = "Construct a range of pdl entities";
|
|
let description = [{
|
|
`pdl.range` operations construct a range from a given set of PDL entities,
|
|
which all share the same underlying element type. For example, a
|
|
`!pdl.range<value>` may be constructed from a list of `!pdl.value`
|
|
or `!pdl.range<value>` entities.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Construct a range of values.
|
|
%valueRange = pdl.range %inputValue, %inputRange : !pdl.value, !pdl.range<value>
|
|
|
|
// Construct a range of types.
|
|
%typeRange = pdl.range %inputType, %inputRange : !pdl.type, !pdl.range<type>
|
|
|
|
// Construct an empty range of types.
|
|
%valueRange = pdl.range : !pdl.range<type>
|
|
```
|
|
|
|
TODO: Range construction is currently limited to rewrites, but it could
|
|
be extended to constraints under certain circustances; i.e., if we can
|
|
determine how to extract the underlying elements. If we can't, e.g. if
|
|
there are multiple sub ranges used for construction, we won't be able
|
|
to determine their sizes during constraint time.
|
|
}];
|
|
|
|
let arguments = (ins Variadic<PDL_AnyType>:$arguments);
|
|
let results = (outs PDL_RangeOf<AnyTypeOf<[PDL_Type, PDL_Value]>>:$result);
|
|
let assemblyFormat = [{
|
|
($arguments^ `:` type($arguments))?
|
|
custom<RangeType>(ref(type($arguments)), type($result))
|
|
attr-dict
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::ReplaceOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_ReplaceOp : PDL_Op<"replace", [
|
|
AttrSizedOperandSegments, HasParent<"pdl::RewriteOp">
|
|
]> {
|
|
let summary = "Mark an input operation as `replaced`";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// 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
|
|
```
|
|
}];
|
|
let arguments = (ins PDL_Operation:$opValue,
|
|
Optional<PDL_Operation>:$replOperation,
|
|
Variadic<PDL_InstOrRangeOf<PDL_Value>>:$replValues);
|
|
let assemblyFormat = [{
|
|
$opValue `with` (`(` $replValues^ `:` type($replValues) `)`)?
|
|
($replOperation^)? attr-dict
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::ResultOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_ResultOp : PDL_Op<"result", [Pure]> {
|
|
let summary = "Extract a result from an operation";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// 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`.
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins PDL_Operation:$parent, I32Attr:$index);
|
|
let results = (outs PDL_Value:$val);
|
|
let assemblyFormat = "$index `of` $parent attr-dict";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::ResultsOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_ResultsOp : PDL_Op<"results", [Pure]> {
|
|
let summary = "Extract a result group from an operation";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// 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
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins PDL_Operation:$parent, OptionalAttr<I32Attr>:$index);
|
|
let results = (outs PDL_InstOrRangeOf<PDL_Value>:$val);
|
|
let assemblyFormat = [{
|
|
($index^)? `of` $parent custom<ResultsValueType>(ref($index), type($val))
|
|
attr-dict
|
|
}];
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::RewriteOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_RewriteOp : PDL_Op<"rewrite", [
|
|
Terminator, HasParent<"pdl::PatternOp">, NoTerminator, NoRegionArguments,
|
|
SingleBlock, AttrSizedOperandSegments,
|
|
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getDefaultDialect"]>
|
|
]> {
|
|
let summary = "Specify the rewrite of a matched pattern";
|
|
let description = [{
|
|
`pdl.rewrite` operations terminate the region of a `pdl.pattern` and specify
|
|
the main rewrite of a `pdl.pattern`, on the optional root operation. The
|
|
rewrite is specified either via a string name (`name`) to a native
|
|
rewrite function, or via the region body. The rewrite region, if specified,
|
|
must contain a single block. If the rewrite is external it functions
|
|
similarly to `pdl.apply_native_rewrite`, and takes 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 leading
|
|
arguments. The root operation, if provided, specifies the starting point in
|
|
the pattern for the subgraph isomorphism search. Pattern matching will proceed
|
|
from this node downward (towards the defining operation) or upward
|
|
(towards the users) until all the operations in the pattern have been matched.
|
|
If the root is omitted, the pdl_interp lowering will automatically select
|
|
the best root of the pdl.rewrite among all the operations in the pattern.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// Specify an external rewrite function:
|
|
pdl.rewrite %root with "myExternalRewriter"(%value : !pdl.value)
|
|
|
|
// Specify a rewrite inline using PDL with the given root:
|
|
pdl.rewrite %root {
|
|
%op = pdl.operation "foo.op"(%arg0, %arg1)
|
|
pdl.replace %root with %op
|
|
}
|
|
|
|
// Specify a rewrite inline using PDL, automatically selecting root:
|
|
pdl.rewrite {
|
|
%op1 = pdl.operation "foo.op"(%arg0, %arg1)
|
|
%op2 = pdl.operation "bar.op"(%arg0, %arg1)
|
|
pdl.replace %root1 with %op1
|
|
pdl.replace %root2 with %op2
|
|
}
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins Optional<PDL_Operation>:$root,
|
|
OptionalAttr<StrAttr>:$name,
|
|
Variadic<PDL_AnyType>:$externalArgs);
|
|
let regions = (region AnyRegion:$bodyRegion);
|
|
let assemblyFormat = [{
|
|
($root^)? (`with` $name^ (`(` $externalArgs^ `:` type($externalArgs) `)`)?)?
|
|
($bodyRegion^)?
|
|
attr-dict-with-keyword
|
|
}];
|
|
let hasRegionVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::TypeOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_TypeOp : PDL_Op<"type"> {
|
|
let summary = "Define a type handle within a pattern";
|
|
let description = [{
|
|
`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:
|
|
|
|
```mlir
|
|
// Define a type:
|
|
%type = pdl.type
|
|
|
|
// Define a type with a constant value:
|
|
%type = pdl.type : i32
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins OptionalAttr<TypeAttr>:$constantType);
|
|
let results = (outs PDL_Type:$result);
|
|
let assemblyFormat = "attr-dict (`:` $constantType^)?";
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// pdl::TypesOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PDL_TypesOp : PDL_Op<"types"> {
|
|
let summary = "Define a range of type handles within a pattern";
|
|
let description = [{
|
|
`pdl.types` operations capture result type constraints of `Value`s, and
|
|
`Operation`s. Instances of this operation define results types of a given
|
|
entity. A `pdl.types` may partially constrain the results by specifying
|
|
an array of `Type`s.
|
|
|
|
Example:
|
|
|
|
```mlir
|
|
// 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]
|
|
```
|
|
}];
|
|
|
|
let arguments = (ins OptionalAttr<TypeArrayAttr>:$constantTypes);
|
|
let results = (outs PDL_RangeOf<PDL_Type>:$result);
|
|
let assemblyFormat = "attr-dict (`:` $constantTypes^)?";
|
|
let hasVerifier = 1;
|
|
}
|
|
|
|
#endif // MLIR_DIALECT_PDL_IR_PDLOPS
|