Files
clang-p2996/mlir/test/lib/Dialect/Test/TestOpsSyntax.td
Krzysztof Drewniak 8955e285e1 [mlir] Add property combinators, initial ODS support (#94732)
While we have had a Properties.td that allowed for defining
non-attribute-backed properties, such properties were not plumbed
through the basic autogeneration facilities available to attributes,
forcing those who want to migrate to the new system to write such code
by hand.

## Potentially breaking changes

- The `setFoo()` methods on `Properties` struct no longer take their
inputs by const reference. Those wishing to pass non-owned values of a
property by reference to constructors and setters should set the
interface type to `const [storageType]&`
- Adapters and operations now define getters and setters for properties
listed in ODS, which may conflict with custom getters.
- Builders now include properties listed in ODS specifications,
potentially conflicting with custom builders with the same type
signature.

## Extensions to the `Property` class

This commit  adds several fields to the `Property` class, including:
- `parser`, `optionalParser`, and `printer` (for parsing/printing
properties of a given type in ODS syntax)
- `storageTypeValueOverride`, an extension of `defaultValue` to allow
the storage and interface type defaults to differ
- `baseProperty` (allowing for classes like `DefaultValuedProperty`)

Existing fields have also had their documentation comments updated.

This commit does not add a `PropertyConstraint` analogous to
`AttrConstraint`, but this is a natural evolution of the work here.

This commit also adds the concrete property kinds `I32Property`,
`I64Property`, `UnitProperty` (and special handling for it like for
UnitAttr), and `BoolProperty`.

## Property combinators

`Properties.td` also now includes several ways to combine properties.

One is `ArrayProperty<Property elem>`, which now stores a
variable-length array of some property as
`SmallVector<elem.storageType>` and uses `ArrayRef<elem.storageType>` as
its interface type. It has `IntArrayProperty` subclasses that change its
conversion to attributes to use `DenseI[N]Attr`s instead of an
`ArrayAttr`.

Similarly, `OptionalProperty<Property p>` wraps a property's storage in
`std::optional<>` and adds a `std::nullopt` default value. In the case
where the underlying property can be parsed optionally but doesn't have
its own default value, `OptionalProperty` can piggyback off the optional
parser to produce a cleaner syntax, as opposed to its general form,
which is either `none` or `some<[value]>`.

(Note that `OptionalProperty` can be nested if desired).

  ## Autogeneration changes

Operations and adaptors now support getters and setters for properties
like those for attributes. Unlike for attributes, there aren't separate
value and attribute forms, since there is no `FooAttr()` available for a
`getFooAttr()` to return.

The largest change is to operation formats. Previously, properties could
only be used in custom directives. Now, they can be used anywhere an
attribute could be used, and have parsers and printers defined in their
tablegen records.

These updates include special `UnitProperty` logic like that used for
`UnitAttr`.

## Misc.

Some attempt has been made to test the new functionality.

This commit takes tentative steps towards updating the documentation to
account for properties. A full update will be in order once any followup
work has been completed and the interfaces have stabilized.

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
Co-authored-by: Christian Ulmann <christianulmann@gmail.com>
2024-07-26 09:35:06 -05:00

764 lines
28 KiB
TableGen

//===-- TestOpsSyntax.td - Operations for testing syntax ---*- 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
//
//===----------------------------------------------------------------------===//
#ifndef TEST_OPS_SYNTAX
#define TEST_OPS_SYNTAX
include "TestAttrDefs.td"
include "TestDialect.td"
include "TestTypeDefs.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/IR/OpBase.td"
class TEST_Op<string mnemonic, list<Trait> traits = []> :
Op<Test_Dialect, mnemonic, traits>;
def WrappingRegionOp : TEST_Op<"wrapping_region",
[SingleBlockImplicitTerminator<"TestReturnOp">]> {
let summary = "wrapping region operation";
let description = [{
Test op wrapping another op in a region, to test calling
parseGenericOperation from the custom parser.
}];
let results = (outs Variadic<AnyType>);
let regions = (region SizedRegion<1>:$region);
let hasCustomAssemblyFormat = 1;
}
def PrettyPrintedRegionOp : TEST_Op<"pretty_printed_region",
[SingleBlockImplicitTerminator<"TestReturnOp">]> {
let summary = "pretty_printed_region operation";
let description = [{
Test-op can be printed either in a "pretty" or "non-pretty" way based on
some criteria. The custom parser parsers both the versions while testing
APIs: parseCustomOperationName & parseGenericOperationAfterOpName.
}];
let arguments = (ins
AnyType:$input1,
AnyType:$input2
);
let results = (outs AnyType);
let regions = (region SizedRegion<1>:$region);
let hasCustomAssemblyFormat = 1;
}
def PolyForOp : TEST_Op<"polyfor", [OpAsmOpInterface]> {
let summary = "polyfor operation";
let description = [{
Test op with multiple region arguments, each argument of index type.
}];
let extraClassDeclaration = [{
void getAsmBlockArgumentNames(mlir::Region &region,
mlir::OpAsmSetValueNameFn setNameFn);
}];
let regions = (region SizedRegion<1>:$region);
let hasCustomAssemblyFormat = 1;
}
def TestAttrWithLoc : TEST_Op<"attr_with_loc"> {
let summary = "op's attribute has a location";
let arguments = (ins AnyAttr:$loc, AnyAttr:$value);
let assemblyFormat = "`(` $value `` custom<OptionalLoc>($loc) `)` attr-dict";
}
// -----
// This is used to test that the fallback for a custom op's parser and printer
// is the dialect parser and printer hooks.
def CustomFormatFallbackOp : TEST_Op<"dialect_custom_format_fallback">;
// Ops related to OIList primitive
def OIListTrivial : TEST_Op<"oilist_with_keywords_only"> {
let arguments = (ins UnitAttr:$keyword, UnitAttr:$otherKeyword,
UnitAttr:$diffNameUnitAttrKeyword);
let assemblyFormat = [{
oilist( `keyword` $keyword
| `otherKeyword` $otherKeyword
| `thirdKeyword` $diffNameUnitAttrKeyword) attr-dict
}];
}
// Ops related to OIList primitive
def OIListTrivialProperties : TEST_Op<"oilist_with_keywords_only_properties"> {
let arguments = (ins UnitProperty:$keyword, UnitProperty:$otherKeyword,
UnitProperty:$diffNameUnitPropertyKeyword);
let assemblyFormat = [{
oilist( `keyword` $keyword
| `otherKeyword` $otherKeyword
| `thirdKeyword` $diffNameUnitPropertyKeyword) attr-dict
}];
}
def OIListSimple : TEST_Op<"oilist_with_simple_args", [AttrSizedOperandSegments]> {
let arguments = (ins Optional<AnyType>:$arg0,
Optional<AnyType>:$arg1,
Optional<AnyType>:$arg2);
let assemblyFormat = [{
oilist( `keyword` $arg0 `:` type($arg0)
| `otherKeyword` $arg1 `:` type($arg1)
| `thirdKeyword` $arg2 `:` type($arg2) ) attr-dict
}];
}
def OIListVariadic : TEST_Op<"oilist_variadic_with_parens", [AttrSizedOperandSegments]> {
let arguments = (ins Variadic<AnyType>:$arg0,
Variadic<AnyType>:$arg1,
Variadic<AnyType>:$arg2);
let assemblyFormat = [{
oilist( `keyword` `(` $arg0 `:` type($arg0) `)`
| `otherKeyword` `(` $arg1 `:` type($arg1) `)`
| `thirdKeyword` `(` $arg2 `:` type($arg2) `)`) attr-dict
}];
}
def OIListCustom : TEST_Op<"oilist_custom", [AttrSizedOperandSegments]> {
let arguments = (ins Variadic<AnyType>:$arg0,
Optional<I32>:$optOperand,
UnitAttr:$nowait);
let assemblyFormat = [{
oilist( `private` `(` $arg0 `:` type($arg0) `)`
| `reduction` custom<CustomOptionalOperand>($optOperand)
| `nowait` $nowait
) attr-dict
}];
}
def OIListAllowedLiteral : TEST_Op<"oilist_allowed_literal"> {
let assemblyFormat = [{
oilist( `foo` | `bar` ) `buzz` attr-dict
}];
}
def TestEllipsisOp : TEST_Op<"ellipsis"> {
let arguments = (ins Variadic<AnyType>:$operands, UnitAttr:$variadic);
let assemblyFormat = [{
`(` $operands (`...` $variadic^)? `)` attr-dict `:` type($operands) `...`
}];
}
def ElseAnchorOp : TEST_Op<"else_anchor"> {
let arguments = (ins Optional<AnyType>:$a);
let assemblyFormat = "`(` (`?`) : (`` $a^ `:` type($a))? `)` attr-dict";
}
// This is used to test that the default dialect is not elided when printing an
// op with dots in the name to avoid parsing ambiguity.
def OpWithDotInNameOp : TEST_Op<"op.with_dot_in_name"> {
let assemblyFormat = "attr-dict";
}
// --------------
//===----------------------------------------------------------------------===//
// Test Op Asm Format
//===----------------------------------------------------------------------===//
def FormatLiteralOp : TEST_Op<"format_literal_op"> {
let assemblyFormat = [{
`keyword_$.` `->` `:` `,` `=` `<` `>` `(` `)` `[` `]` `` `(` ` ` `)`
`?` `+` `*` `{` `\n` `}` attr-dict
}];
}
// Test that we elide attributes that are within the syntax.
def FormatAttrOp : TEST_Op<"format_attr_op"> {
let arguments = (ins I64Attr:$attr);
let assemblyFormat = "$attr attr-dict";
}
// Test that we elide optional attributes that are within the syntax.
def FormatOptAttrAOp : TEST_Op<"format_opt_attr_op_a"> {
let arguments = (ins OptionalAttr<I64Attr>:$opt_attr);
let assemblyFormat = "(`(` $opt_attr^ `)` )? attr-dict";
}
def FormatOptAttrBOp : TEST_Op<"format_opt_attr_op_b"> {
let arguments = (ins OptionalAttr<I64Attr>:$opt_attr);
let assemblyFormat = "($opt_attr^)? attr-dict";
}
// Test that we format symbol name attributes properly.
def FormatSymbolNameAttrOp : TEST_Op<"format_symbol_name_attr_op"> {
let arguments = (ins SymbolNameAttr:$attr);
let assemblyFormat = "$attr attr-dict";
}
// Test that we format optional symbol name attributes properly.
def FormatOptSymbolNameAttrOp : TEST_Op<"format_opt_symbol_name_attr_op"> {
let arguments = (ins OptionalAttr<SymbolNameAttr>:$opt_attr);
let assemblyFormat = "($opt_attr^)? attr-dict";
}
// Test that we format optional symbol reference attributes properly.
def FormatOptSymbolRefAttrOp : TEST_Op<"format_opt_symbol_ref_attr_op"> {
let arguments = (ins OptionalAttr<SymbolRefAttr>:$opt_attr);
let assemblyFormat = "($opt_attr^)? attr-dict";
}
// Test that we elide attributes that are within the syntax.
def FormatAttrDictWithKeywordOp : TEST_Op<"format_attr_dict_w_keyword"> {
let arguments = (ins I64Attr:$attr, OptionalAttr<I64Attr>:$opt_attr);
let assemblyFormat = "attr-dict-with-keyword";
}
// Test that we don't need to provide types in the format if they are buildable.
def FormatBuildableTypeOp : TEST_Op<"format_buildable_type_op"> {
let arguments = (ins I64:$buildable);
let results = (outs I64:$buildable_res);
let assemblyFormat = "$buildable attr-dict";
}
// Test various mixings of region formatting.
class FormatRegionBase<string suffix, string fmt>
: TEST_Op<"format_region_" # suffix # "_op"> {
let regions = (region AnyRegion:$region);
let assemblyFormat = fmt;
}
def FormatRegionAOp : FormatRegionBase<"a", [{
regions attr-dict
}]>;
def FormatRegionBOp : FormatRegionBase<"b", [{
$region attr-dict
}]>;
def FormatRegionCOp : FormatRegionBase<"c", [{
(`region` $region^)? attr-dict
}]>;
class FormatVariadicRegionBase<string suffix, string fmt>
: TEST_Op<"format_variadic_region_" # suffix # "_op"> {
let regions = (region VariadicRegion<AnyRegion>:$regions);
let assemblyFormat = fmt;
}
def FormatVariadicRegionAOp : FormatVariadicRegionBase<"a", [{
$regions attr-dict
}]>;
def FormatVariadicRegionBOp : FormatVariadicRegionBase<"b", [{
($regions^ `found_regions`)? attr-dict
}]>;
class FormatRegionImplicitTerminatorBase<string suffix, string fmt>
: TEST_Op<"format_implicit_terminator_region_" # suffix # "_op",
[SingleBlockImplicitTerminator<"TestReturnOp">]> {
let regions = (region AnyRegion:$region);
let assemblyFormat = fmt;
}
def FormatFormatRegionImplicitTerminatorAOp
: FormatRegionImplicitTerminatorBase<"a", [{
$region attr-dict
}]>;
// Test various mixings of result type formatting.
class FormatResultBase<string suffix, string fmt>
: TEST_Op<"format_result_" # suffix # "_op"> {
let results = (outs I64:$buildable_res, AnyMemRef:$result);
let assemblyFormat = fmt;
}
def FormatResultAOp : FormatResultBase<"a", [{
type($result) attr-dict
}]>;
def FormatResultBOp : FormatResultBase<"b", [{
type(results) attr-dict
}]>;
def FormatResultCOp : FormatResultBase<"c", [{
functional-type($buildable_res, $result) attr-dict
}]>;
def FormatVariadicResult : TEST_Op<"format_variadic_result"> {
let results = (outs Variadic<I64>:$result);
let assemblyFormat = [{ `:` type($result) attr-dict}];
}
def FormatMultipleVariadicResults : TEST_Op<"format_multiple_variadic_results",
[AttrSizedResultSegments]> {
let results = (outs Variadic<I64>:$result0, Variadic<AnyType>:$result1);
let assemblyFormat = [{
`:` `(` type($result0) `)` `,` `(` type($result1) `)` attr-dict
}];
}
// Test various mixings of operand type formatting.
class FormatOperandBase<string suffix, string fmt>
: TEST_Op<"format_operand_" # suffix # "_op"> {
let arguments = (ins I64:$buildable, AnyMemRef:$operand);
let assemblyFormat = fmt;
}
def FormatOperandAOp : FormatOperandBase<"a", [{
operands `:` type(operands) attr-dict
}]>;
def FormatOperandBOp : FormatOperandBase<"b", [{
operands `:` type($operand) attr-dict
}]>;
def FormatOperandCOp : FormatOperandBase<"c", [{
$buildable `,` $operand `:` type(operands) attr-dict
}]>;
def FormatOperandDOp : FormatOperandBase<"d", [{
$buildable `,` $operand `:` type($operand) attr-dict
}]>;
def FormatOperandEOp : FormatOperandBase<"e", [{
$buildable `,` $operand `:` type($buildable) `,` type($operand) attr-dict
}]>;
def FormatSuccessorAOp : TEST_Op<"format_successor_a_op", [Terminator]> {
let successors = (successor VariadicSuccessor<AnySuccessor>:$targets);
let assemblyFormat = "$targets attr-dict";
}
def FormatVariadicOperand : TEST_Op<"format_variadic_operand"> {
let arguments = (ins Variadic<I64>:$operand);
let assemblyFormat = [{ $operand `:` type($operand) attr-dict}];
}
def FormatVariadicOfVariadicOperand
: TEST_Op<"format_variadic_of_variadic_operand"> {
let arguments = (ins
VariadicOfVariadic<I64, "operand_segments">:$operand,
DenseI32ArrayAttr:$operand_segments
);
let assemblyFormat = [{ $operand `:` type($operand) attr-dict}];
}
def FormatMultipleVariadicOperands :
TEST_Op<"format_multiple_variadic_operands", [AttrSizedOperandSegments]> {
let arguments = (ins Variadic<I64>:$operand0, Variadic<AnyType>:$operand1);
let assemblyFormat = [{
` ` `(` $operand0 `)` `,` `(` $operand1 `:` type($operand1) `)` attr-dict
}];
}
// Test various mixings of optional operand and result type formatting.
class FormatOptionalOperandResultOpBase<string suffix, string fmt>
: TEST_Op<"format_optional_operand_result_" # suffix # "_op",
[AttrSizedOperandSegments]> {
let arguments = (ins Optional<I64>:$optional, Variadic<I64>:$variadic);
let results = (outs Optional<I64>:$optional_res);
let assemblyFormat = fmt;
}
def FormatOptionalOperandResultAOp : FormatOptionalOperandResultOpBase<"a", [{
`(` $optional `:` type($optional) `)` `:` type($optional_res)
(`[` $variadic^ `]`)? attr-dict
}]>;
def FormatOptionalOperandResultBOp : FormatOptionalOperandResultOpBase<"b", [{
(`(` $optional^ `:` type($optional) `)`)? `:` type($optional_res)
(`[` $variadic^ `]`)? attr-dict
}]>;
// Test optional result type formatting.
class FormatOptionalResultOpBase<string suffix, string fmt>
: TEST_Op<"format_optional_result_" # suffix # "_op",
[AttrSizedResultSegments]> {
let results = (outs Optional<I64>:$optional, Variadic<I64>:$variadic);
let assemblyFormat = fmt;
}
def FormatOptionalResultAOp : FormatOptionalResultOpBase<"a", [{
(`:` type($optional)^ `->` type($variadic))? attr-dict
}]>;
def FormatOptionalResultBOp : FormatOptionalResultOpBase<"b", [{
(`:` type($optional) `->` type($variadic)^)? attr-dict
}]>;
def FormatOptionalResultCOp : FormatOptionalResultOpBase<"c", [{
(`:` functional-type($optional, $variadic)^)? attr-dict
}]>;
def FormatOptionalResultDOp
: TEST_Op<"format_optional_result_d_op" > {
let results = (outs Optional<F80>:$optional);
let assemblyFormat = "(`:` type($optional)^)? attr-dict";
}
def FormatTwoVariadicOperandsNoBuildableTypeOp
: TEST_Op<"format_two_variadic_operands_no_buildable_type_op",
[AttrSizedOperandSegments]> {
let arguments = (ins Variadic<AnyType>:$a,
Variadic<AnyType>:$b);
let assemblyFormat = [{
`(` $a `:` type($a) `)` `->` `(` $b `:` type($b) `)` attr-dict
}];
}
def FormatInferVariadicTypeFromNonVariadic
: TEST_Op<"format_infer_variadic_type_from_non_variadic",
[SameOperandsAndResultType]> {
let arguments = (ins Variadic<AnyType>:$args);
let results = (outs AnyType:$result);
let assemblyFormat = "operands attr-dict `:` type($result)";
}
def FormatOptionalUnitAttr : TEST_Op<"format_optional_unit_attribute"> {
let arguments = (ins UnitAttr:$is_optional);
let assemblyFormat = "(`is_optional` $is_optional^)? attr-dict";
}
def FormatOptionalUnitAttrNoElide
: TEST_Op<"format_optional_unit_attribute_no_elide"> {
let arguments = (ins UnitAttr:$is_optional);
let assemblyFormat = "($is_optional^)? attr-dict";
}
def FormatOptionalUnitProperty : TEST_Op<"format_optional_unit_property"> {
let arguments = (ins UnitProperty:$is_optional);
let assemblyFormat = "(`is_optional` $is_optional^)? attr-dict";
}
def FormatOptionalUnitPropertyNoElide
: TEST_Op<"format_optional_unit_property_no_elide"> {
let arguments = (ins UnitProperty:$is_optional);
let assemblyFormat = "($is_optional^)? attr-dict";
}
def FormatOptionalEnumAttr : TEST_Op<"format_optional_enum_attr"> {
let arguments = (ins OptionalAttr<SomeI64Enum>:$attr);
let assemblyFormat = "($attr^)? attr-dict";
}
def FormatOptionalDefaultAttrs : TEST_Op<"format_optional_default_attrs"> {
let arguments = (ins DefaultValuedStrAttr<StrAttr, "default">:$str,
DefaultValuedStrAttr<SymbolNameAttr, "default">:$sym,
DefaultValuedAttr<SomeI64Enum, "SomeI64Enum::case5">:$e);
let assemblyFormat = "($str^)? ($sym^)? ($e^)? attr-dict";
}
def FormatOptionalWithElse : TEST_Op<"format_optional_else"> {
let arguments = (ins UnitAttr:$isFirstBranchPresent);
let assemblyFormat = "(`then` $isFirstBranchPresent^):(`else`)? attr-dict";
}
def FormatCompoundAttr : TEST_Op<"format_compound_attr"> {
let arguments = (ins CompoundAttrA:$compound);
let assemblyFormat = "$compound attr-dict-with-keyword";
}
def FormatNestedAttr : TEST_Op<"format_nested_attr"> {
let arguments = (ins CompoundAttrNested:$nested);
let assemblyFormat = "$nested attr-dict-with-keyword";
}
def FormatNestedCompoundAttr : TEST_Op<"format_cpmd_nested_attr"> {
let arguments = (ins CompoundNestedOuter:$nested);
let assemblyFormat = "`nested` $nested attr-dict-with-keyword";
}
def FormatMaybeEmptyType : TEST_Op<"format_maybe_empty_type"> {
let arguments = (ins TestTypeOptionalValueType:$in);
let assemblyFormat = "$in `:` type($in) attr-dict";
}
def FormatQualifiedCompoundAttr : TEST_Op<"format_qual_cpmd_nested_attr"> {
let arguments = (ins CompoundNestedOuter:$nested);
let assemblyFormat = "`nested` qualified($nested) attr-dict-with-keyword";
}
def FormatNestedType : TEST_Op<"format_cpmd_nested_type"> {
let arguments = (ins CompoundNestedOuterType:$nested);
let assemblyFormat = "$nested `nested` type($nested) attr-dict-with-keyword";
}
def FormatQualifiedNestedType : TEST_Op<"format_qual_cpmd_nested_type"> {
let arguments = (ins CompoundNestedOuterType:$nested);
let assemblyFormat = "$nested `nested` qualified(type($nested)) attr-dict-with-keyword";
}
//===----------------------------------------------------------------------===//
// Custom Directives
def FormatCustomDirectiveOperands
: TEST_Op<"format_custom_directive_operands", [AttrSizedOperandSegments]> {
let arguments = (ins I64:$operand, Optional<I64>:$optOperand,
Variadic<I64>:$varOperands);
let assemblyFormat = [{
custom<CustomDirectiveOperands>(
$operand, $optOperand, $varOperands
)
attr-dict
}];
}
def FormatCustomDirectiveOperandsAndTypes
: TEST_Op<"format_custom_directive_operands_and_types",
[AttrSizedOperandSegments]> {
let arguments = (ins AnyType:$operand, Optional<AnyType>:$optOperand,
Variadic<AnyType>:$varOperands);
let assemblyFormat = [{
custom<CustomDirectiveOperandsAndTypes>(
$operand, $optOperand, $varOperands,
type($operand), type($optOperand), type($varOperands)
)
attr-dict
}];
}
def FormatCustomDirectiveRegions : TEST_Op<"format_custom_directive_regions"> {
let regions = (region AnyRegion:$region, VariadicRegion<AnyRegion>:$other_regions);
let assemblyFormat = [{
custom<CustomDirectiveRegions>(
$region, $other_regions
)
attr-dict
}];
}
def FormatCustomDirectiveResults
: TEST_Op<"format_custom_directive_results", [AttrSizedResultSegments]> {
let results = (outs AnyType:$result, Optional<AnyType>:$optResult,
Variadic<AnyType>:$varResults);
let assemblyFormat = [{
custom<CustomDirectiveResults>(
type($result), type($optResult), type($varResults)
)
attr-dict
}];
}
def FormatCustomDirectiveResultsWithTypeRefs
: TEST_Op<"format_custom_directive_results_with_type_refs",
[AttrSizedResultSegments]> {
let results = (outs AnyType:$result, Optional<AnyType>:$optResult,
Variadic<AnyType>:$varResults);
let assemblyFormat = [{
custom<CustomDirectiveResults>(
type($result), type($optResult), type($varResults)
)
custom<CustomDirectiveWithTypeRefs>(
ref(type($result)), ref(type($optResult)), ref(type($varResults))
)
attr-dict
}];
}
def FormatCustomDirectiveWithOptionalOperandRef
: TEST_Op<"format_custom_directive_with_optional_operand_ref"> {
let arguments = (ins Optional<I64>:$optOperand);
let assemblyFormat = [{
($optOperand^)? `:`
custom<CustomDirectiveOptionalOperandRef>(ref($optOperand))
attr-dict
}];
}
def FormatCustomDirectiveSuccessors
: TEST_Op<"format_custom_directive_successors", [Terminator]> {
let successors = (successor AnySuccessor:$successor,
VariadicSuccessor<AnySuccessor>:$successors);
let assemblyFormat = [{
custom<CustomDirectiveSuccessors>(
$successor, $successors
)
attr-dict
}];
}
def FormatCustomDirectiveAttributes
: TEST_Op<"format_custom_directive_attributes"> {
let arguments = (ins I64Attr:$attr, OptionalAttr<I64Attr>:$optAttr);
let assemblyFormat = [{
custom<CustomDirectiveAttributes>(
$attr, $optAttr
)
attr-dict
}];
}
def FormatCustomDirectiveSpacing
: TEST_Op<"format_custom_directive_spacing"> {
let arguments = (ins StrAttr:$attr1, StrAttr:$attr2);
let assemblyFormat = [{
custom<CustomDirectiveSpacing>($attr1)
custom<CustomDirectiveSpacing>($attr2)
attr-dict
}];
}
def FormatCustomDirectiveAttrDict
: TEST_Op<"format_custom_directive_attrdict"> {
let arguments = (ins I64Attr:$attr, OptionalAttr<I64Attr>:$optAttr);
let assemblyFormat = [{
custom<CustomDirectiveAttrDict>( attr-dict )
}];
}
def FormatLiteralFollowingOptionalGroup
: TEST_Op<"format_literal_following_optional_group"> {
let arguments = (ins TypeAttr:$type, OptionalAttr<AnyAttr>:$value);
let assemblyFormat = "(`(` $value^ `)`)? `:` $type attr-dict";
}
//===----------------------------------------------------------------------===//
// AllTypesMatch type inference
def FormatAllTypesMatchVarOp : TEST_Op<"format_all_types_match_var", [
AllTypesMatch<["value1", "value2", "result"]>
]> {
let arguments = (ins AnyType:$value1, AnyType:$value2);
let results = (outs AnyType:$result);
let assemblyFormat = "attr-dict $value1 `,` $value2 `:` type($value1)";
}
def FormatAllTypesMatchAttrOp : TEST_Op<"format_all_types_match_attr", [
AllTypesMatch<["value1", "value2", "result"]>
]> {
let arguments = (ins TypedAttrInterface:$value1, AnyType:$value2);
let results = (outs AnyType:$result);
let assemblyFormat = "attr-dict $value1 `,` $value2";
}
//===----------------------------------------------------------------------===//
// TypesMatchWith type inference
def FormatTypesMatchVarOp : TEST_Op<"format_types_match_var", [
TypesMatchWith<"result type matches operand", "value", "result", "$_self">
]> {
let arguments = (ins AnyType:$value);
let results = (outs AnyType:$result);
let assemblyFormat = "attr-dict $value `:` type($value)";
}
def FormatTypesMatchVariadicOp : TEST_Op<"format_types_match_variadic", [
RangedTypesMatchWith<"result type matches operand", "value", "result",
"llvm::make_range($_self.begin(), $_self.end())">
]> {
let arguments = (ins Variadic<AnyType>:$value);
let results = (outs Variadic<AnyType>:$result);
let assemblyFormat = "attr-dict $value `:` type($value)";
}
def FormatTypesMatchAttrOp : TEST_Op<"format_types_match_attr", [
TypesMatchWith<"result type matches constant", "value", "result", "$_self">
]> {
let arguments = (ins TypedAttrInterface:$value);
let results = (outs AnyType:$result);
let assemblyFormat = "attr-dict $value";
}
def FormatTypesMatchContextOp : TEST_Op<"format_types_match_context", [
TypesMatchWith<"tuple result type matches operand type", "value", "result",
"::mlir::TupleType::get($_ctxt, $_self)">
]> {
let arguments = (ins AnyType:$value);
let results = (outs AnyType:$result);
let assemblyFormat = "attr-dict $value `:` type($value)";
}
//===----------------------------------------------------------------------===//
// InferTypeOpInterface type inference in assembly format
def FormatInferTypeOp : TEST_Op<"format_infer_type", [InferTypeOpInterface]> {
let results = (outs AnyType);
let assemblyFormat = "attr-dict";
let extraClassDeclaration = [{
static ::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
inferredReturnTypes.assign({::mlir::IntegerType::get(context, 16)});
return ::mlir::success();
}
}];
}
// Check that formatget supports DeclareOpInterfaceMethods.
def FormatInferType2Op : TEST_Op<"format_infer_type2", [DeclareOpInterfaceMethods<InferTypeOpInterface>]> {
let results = (outs AnyType);
let assemblyFormat = "attr-dict";
}
// Base class for testing mixing allOperandTypes, allOperands, and
// inferResultTypes.
class FormatInferAllTypesBaseOp<string mnemonic, list<Trait> traits = []>
: TEST_Op<mnemonic, [InferTypeOpInterface] # traits> {
let arguments = (ins Variadic<AnyType>:$args);
let results = (outs Variadic<AnyType>:$outs);
let extraClassDeclaration = [{
static ::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
::mlir::TypeRange operandTypes = operands.getTypes();
inferredReturnTypes.assign(operandTypes.begin(), operandTypes.end());
return ::mlir::success();
}
}];
}
// Test inferReturnTypes is called when allOperandTypes and allOperands is true.
def FormatInferTypeAllOperandsAndTypesOp
: FormatInferAllTypesBaseOp<"format_infer_type_all_operands_and_types"> {
let assemblyFormat = "`(` operands `)` attr-dict `:` type(operands)";
}
// Test inferReturnTypes is called when allOperandTypes is true and there is one
// ODS operand.
def FormatInferTypeAllOperandsAndTypesOneOperandOp
: FormatInferAllTypesBaseOp<"format_infer_type_all_types_one_operand"> {
let assemblyFormat = "`(` $args `)` attr-dict `:` type(operands)";
}
// Test inferReturnTypes is called when allOperandTypes is true and there are
// more than one ODS operands.
def FormatInferTypeAllOperandsAndTypesTwoOperandsOp
: FormatInferAllTypesBaseOp<"format_infer_type_all_types_two_operands",
[SameVariadicOperandSize]> {
let arguments = (ins Variadic<AnyType>:$args0, Variadic<AnyType>:$args1);
let assemblyFormat = "`(` $args0 `)` `(` $args1 `)` attr-dict `:` type(operands)";
}
// Test inferReturnTypes is called when allOperands is true and operand types
// are separately specified.
def FormatInferTypeAllTypesOp
: FormatInferAllTypesBaseOp<"format_infer_type_all_types"> {
let assemblyFormat = "`(` operands `)` attr-dict `:` type($args)";
}
// Test inferReturnTypes coupled with regions.
def FormatInferTypeRegionsOp
: TEST_Op<"format_infer_type_regions", [InferTypeOpInterface]> {
let results = (outs Variadic<AnyType>:$outs);
let regions = (region AnyRegion:$region);
let assemblyFormat = "$region attr-dict";
let extraClassDeclaration = [{
static ::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
if (regions.empty())
return ::mlir::failure();
auto types = regions.front()->getArgumentTypes();
inferredReturnTypes.assign(types.begin(), types.end());
return ::mlir::success();
}
}];
}
// Test inferReturnTypes coupled with variadic operands (operandSegmentSizes).
def FormatInferTypeVariadicOperandsOp
: TEST_Op<"format_infer_type_variadic_operands",
[InferTypeOpInterface, AttrSizedOperandSegments]> {
let arguments = (ins Variadic<I32>:$a, Variadic<I64>:$b);
let results = (outs Variadic<AnyType>:$outs);
let assemblyFormat = "`(` $a `:` type($a) `)` `(` $b `:` type($b) `)` attr-dict";
let extraClassDeclaration = [{
static ::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
FormatInferTypeVariadicOperandsOpAdaptor adaptor(
operands, attributes, *properties.as<Properties *>(), {});
auto aTypes = adaptor.getA().getTypes();
auto bTypes = adaptor.getB().getTypes();
inferredReturnTypes.append(aTypes.begin(), aTypes.end());
inferredReturnTypes.append(bTypes.begin(), bTypes.end());
return ::mlir::success();
}
}];
}
#endif // TEST_OPS_SYNTAX