llvm/mlir/test/lib/Dialect/Test/TestOpsSyntax.td


//===-- 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