//===-- TestOps.td - Test dialect operation definitions ----*- 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 #define TEST_OPS include "TestDialect.td" include "TestInterfaces.td" include "mlir/Dialect/DLTI/DLTIBase.td" include "mlir/Dialect/Linalg/IR/LinalgInterfaces.td" include "mlir/IR/EnumAttr.td" include "mlir/IR/OpBase.td" include "mlir/IR/OpAsmInterface.td" include "mlir/IR/PatternBase.td" include "mlir/IR/RegionKindInterface.td" include "mlir/IR/SymbolInterfaces.td" include "mlir/Interfaces/CallInterfaces.td" include "mlir/Interfaces/ControlFlowInterfaces.td" include "mlir/Interfaces/CopyOpInterface.td" include "mlir/Interfaces/DataLayoutInterfaces.td" include "mlir/Interfaces/InferIntRangeInterface.td" include "mlir/Interfaces/InferTypeOpInterface.td" include "mlir/Interfaces/LoopLikeInterface.td" include "mlir/Interfaces/SideEffectInterfaces.td" // Include the attribute definitions. include "TestAttrDefs.td" // Include the type definitions. include "TestTypeDefs.td" class TEST_Op traits = []> : Op; //===----------------------------------------------------------------------===// // Test Types //===----------------------------------------------------------------------===// def IntTypesOp : TEST_Op<"int_types"> { let results = (outs AnyI16:$any_i16, SI32:$si32, UI64:$ui64, AnyInteger:$any_int ); } def ComplexF64 : Complex; def ComplexOp : TEST_Op<"complex_f64"> { let results = (outs ComplexF64); } def ComplexTensorOp : TEST_Op<"complex_f64_tensor"> { let results = (outs TensorOf<[ComplexF64]>); } def TupleOp : TEST_Op<"tuple_32_bit"> { let results = (outs TupleOf<[I32, F32]>); } def NestedTupleOp : TEST_Op<"nested_tuple_32_bit"> { let results = (outs NestedTupleOf<[I32, F32]>); } def TakesStaticMemRefOp : TEST_Op<"takes_static_memref"> { let arguments = (ins AnyStaticShapeMemRef:$x); } def RankLessThan2I8F32MemRefOp : TEST_Op<"rank_less_than_2_I8_F32_memref"> { let results = (outs MemRefRankOf<[I8, F32], [0, 1]>); } def NDTensorOfOp : TEST_Op<"nd_tensor_of"> { let arguments = (ins 0DTensorOf<[F32]>:$arg0, 1DTensorOf<[F32]>:$arg1, 2DTensorOf<[I16]>:$arg2, 3DTensorOf<[I16]>:$arg3, 4DTensorOf<[I16]>:$arg4 ); } def RankedTensorOp : TEST_Op<"ranked_tensor_op"> { let arguments = (ins AnyRankedTensor:$input); } def MultiTensorRankOf : TEST_Op<"multi_tensor_rank_of"> { let arguments = (ins TensorRankOf<[I8, I32, F32], [0, 1]>:$arg0 ); } def TEST_TestType : DialectType()">, "test">, BuildableType<"$_builder.getType<::test::TestType>()">; //===----------------------------------------------------------------------===// // Test Symbols //===----------------------------------------------------------------------===// def SymbolOp : TEST_Op<"symbol", [Symbol]> { let summary = "operation which defines a new symbol"; let arguments = (ins StrAttr:$sym_name, OptionalAttr:$sym_visibility); } def SymbolScopeOp : TEST_Op<"symbol_scope", [SymbolTable, SingleBlockImplicitTerminator<"TerminatorOp">]> { let summary = "operation which defines a new symbol table"; let regions = (region SizedRegion<1>:$region); } def SymbolTableRegionOp : TEST_Op<"symbol_table_region", [SymbolTable]> { let summary = "operation which defines a new symbol table without a " "restriction on a terminator"; let regions = (region SizedRegion<1>:$region); } //===----------------------------------------------------------------------===// // Test Operands //===----------------------------------------------------------------------===// def MixedNormalVariadicOperandOp : TEST_Op< "mixed_normal_variadic_operand", [SameVariadicOperandSize]> { let arguments = (ins Variadic:$input1, AnyTensor:$input2, Variadic:$input3 ); } def VariadicWithSameOperandsResult : TEST_Op<"variadic_with_same_operand_results", [SameOperandsAndResultType]> { let arguments = (ins Variadic); let results = (outs AnySignlessInteger:$result); } def SameOperandsResultType : TEST_Op< "same_operand_result_type", [SameOperandsAndResultType]> { let arguments = (ins AnyTensor:$operand); let results = (outs AnyTensor:$result); } //===----------------------------------------------------------------------===// // Test Results //===----------------------------------------------------------------------===// def MixedNormalVariadicResults : TEST_Op< "mixed_normal_variadic_result", [SameVariadicResultSize]> { let results = (outs Variadic:$output1, AnyTensor:$output2, Variadic:$output3 ); } //===----------------------------------------------------------------------===// // Test Attributes //===----------------------------------------------------------------------===// def AnyAttrOfOp : TEST_Op<"any_attr_of_i32_str"> { let arguments = (ins AnyAttrOf<[I32Attr, StrAttr]>:$attr); } def NonNegIntAttrOp : TEST_Op<"non_negative_int_attr"> { let arguments = (ins Confined:$i32attr, Confined:$i64attr ); } def PositiveIntAttrOp : TEST_Op<"positive_int_attr"> { let arguments = (ins Confined:$i32attr, Confined:$i64attr ); } def TypeArrayAttrOp : TEST_Op<"type_array_attr"> { let arguments = (ins TypeArrayAttr:$attr); } def TypeArrayAttrWithDefaultOp : TEST_Op<"type_array_attr_with_default"> { let arguments = (ins DefaultValuedAttr:$attr); } def TypeStringAttrWithTypeOp : TEST_Op<"string_attr_with_type"> { let arguments = (ins TypedStrAttr:$attr); let assemblyFormat = "$attr attr-dict"; } def I32Case5: I32EnumAttrCase<"case5", 5>; def I32Case10: I32EnumAttrCase<"case10", 10>; def SomeI32Enum: I32EnumAttr< "SomeI32Enum", "", [I32Case5, I32Case10]>; def I32EnumAttrOp : TEST_Op<"i32_enum_attr"> { let arguments = (ins SomeI32Enum:$attr); let results = (outs I32:$val); } def I64Case5: I64EnumAttrCase<"case5", 5>; def I64Case10: I64EnumAttrCase<"case10", 10>; def SomeI64Enum: I64EnumAttr< "SomeI64Enum", "", [I64Case5, I64Case10]>; def I64EnumAttrOp : TEST_Op<"i64_enum_attr"> { let arguments = (ins SomeI64Enum:$attr); let results = (outs I32:$val); } def IntAttrOp : TEST_Op<"int_attrs"> { let arguments = (ins AnyI32Attr:$any_i32_attr, IndexAttr:$index_attr, UI32Attr:$ui32_attr, SI32Attr:$si32_attr ); } def FloatElementsAttrOp : TEST_Op<"float_elements_attr"> { let arguments = (ins RankedF32ElementsAttr<[2]>:$scalar_f32_attr, RankedF64ElementsAttr<[4, 8]>:$tensor_f64_attr ); } // A pattern that updates dense<[3.0, 4.0]> to dense<[5.0, 6.0]>. // This tests both matching and generating float elements attributes. def UpdateFloatElementsAttr : Pat< (FloatElementsAttrOp ConstantAttr, "{3.0f, 4.0f}">:$f32attr, $f64attr), (FloatElementsAttrOp ConstantAttr, "{5.0f, 6.0f}">:$f32attr, $f64attr)>; def IntElementsAttrOp : TEST_Op<"int_elements_attr"> { let arguments = (ins AnyI32ElementsAttr:$any_i32_attr, I32ElementsAttr:$i32_attr ); } def RankedIntElementsAttrOp : TEST_Op<"ranked_int_elements_attr"> { let arguments = (ins RankedI32ElementsAttr<[2]>:$vector_i32_attr, RankedI64ElementsAttr<[4, 8]>:$matrix_i64_attr ); } def DerivedTypeAttrOp : TEST_Op<"derived_type_attr", []> { let results = (outs AnyTensor:$output); DerivedTypeAttr element_dtype = DerivedTypeAttr<"return getElementTypeOrSelf(getOutput().getType());">; DerivedAttr size = DerivedAttr<"int", "return getOutput().getType().cast().getSizeInBits();", "$_builder.getI32IntegerAttr($_self)">; } def StringElementsAttrOp : TEST_Op<"string_elements_attr"> { let arguments = (ins StringElementsAttr:$scalar_string_attr ); } def DenseArrayAttrOp : TEST_Op<"dense_array_attr"> { let arguments = (ins DenseI8ArrayAttr:$i8attr, DenseI16ArrayAttr:$i16attr, DenseI32ArrayAttr:$i32attr, DenseI64ArrayAttr:$i64attr, DenseF32ArrayAttr:$f32attr, DenseF64ArrayAttr:$f64attr, DenseI32ArrayAttr:$emptyattr ); let assemblyFormat = [{ `i8attr` `=` $i8attr `i16attr` `=` $i16attr `i32attr` `=` $i32attr `i64attr` `=` $i64attr `f32attr` `=` $f32attr `f64attr` `=` $f64attr `emptyattr` `=` $emptyattr attr-dict }]; } //===----------------------------------------------------------------------===// // Test Enum Attributes //===----------------------------------------------------------------------===// // Define the C++ enum. def TestEnum : I32EnumAttr<"TestEnum", "a test enum", [ I32EnumAttrCase<"First", 0, "first">, I32EnumAttrCase<"Second", 1, "second">, I32EnumAttrCase<"Third", 2, "third">, ]> { let genSpecializedAttr = 0; let cppNamespace = "test"; } // Define the enum attribute. def TestEnumAttr : EnumAttr; // Define an op that contains the enum attribute. def OpWithEnum : TEST_Op<"op_with_enum"> { let arguments = (ins TestEnumAttr:$value, OptionalAttr:$tag); let assemblyFormat = "$value (`tag` $tag^)? attr-dict"; } // Define a pattern that matches and creates an enum attribute. def : Pat<(OpWithEnum ConstantAttr:$value, ConstantAttr:$tag), (OpWithEnum ConstantAttr, ConstantAttr)>; //===----------------------------------------------------------------------===// // Test Bit Enum Attributes //===----------------------------------------------------------------------===// // Define the C++ enum. def TestBitEnum : I32BitEnumAttr<"TestBitEnum", "a test bit enum", [ I32BitEnumAttrCaseBit<"Read", 0, "read">, I32BitEnumAttrCaseBit<"Write", 1, "write">, I32BitEnumAttrCaseBit<"Execute", 2, "execute">, ]> { let genSpecializedAttr = 0; let cppNamespace = "test"; let separator = ", "; } // Define the enum attribute. def TestBitEnumAttr : EnumAttr { let assemblyFormat = "`<` $value `>`"; } // Define an op that contains the enum attribute. def OpWithBitEnum : TEST_Op<"op_with_bit_enum"> { let arguments = (ins TestBitEnumAttr:$value, OptionalAttr:$tag); let assemblyFormat = "$value (`tag` $tag^)? attr-dict"; } // Define an enum with a different separator def TestBitEnumVerticalBar : I32BitEnumAttr<"TestBitEnumVerticalBar", "another test bit enum", [ I32BitEnumAttrCaseBit<"User", 0, "user">, I32BitEnumAttrCaseBit<"Group", 1, "group">, I32BitEnumAttrCaseBit<"Other", 2, "other">, ]> { let genSpecializedAttr = 0; let cppNamespace = "test"; let separator = " | "; } def TestBitEnumVerticalBarAttr : EnumAttr { let assemblyFormat = "`<` $value `>`"; } // Define an op that contains the enum attribute. def OpWithBitEnumVerticalBar : TEST_Op<"op_with_bit_enum_vbar"> { let arguments = (ins TestBitEnumVerticalBarAttr:$value, OptionalAttr:$tag); let assemblyFormat = "$value (`tag` $tag^)? attr-dict"; } //===----------------------------------------------------------------------===// // Test Attribute Constraints //===----------------------------------------------------------------------===// def SymbolRefOp : TEST_Op<"symbol_ref_attr"> { let arguments = (ins Confined]>:$symbol ); } //===----------------------------------------------------------------------===// // Test Regions //===----------------------------------------------------------------------===// def OneRegionOp : TEST_Op<"one_region_op", []> { let regions = (region AnyRegion); } def TwoRegionOp : TEST_Op<"two_region_op", []> { let regions = (region AnyRegion, AnyRegion); } def SizedRegionOp : TEST_Op<"sized_region_op", []> { let regions = (region SizedRegion<2>:$my_region, SizedRegion<1>); } def VariadicRegionInferredTypesOp : TEST_Op<"variadic_region_inferred", [InferTypeOpInterface]> { let regions = (region VariadicRegion:$bodies); let results = (outs Variadic); let extraClassDeclaration = [{ static mlir::LogicalResult inferReturnTypes(mlir::MLIRContext *context, llvm::Optional<::mlir::Location> location, mlir::ValueRange operands, mlir::DictionaryAttr attributes, mlir::RegionRange regions, llvm::SmallVectorImpl &inferredReturnTypes) { inferredReturnTypes.assign({mlir::IntegerType::get(context, 16)}); return mlir::success(); } }]; } //===----------------------------------------------------------------------===// // NoTerminator Operation //===----------------------------------------------------------------------===// def SingleNoTerminatorOp : TEST_Op<"single_no_terminator_op", GraphRegionNoTerminator.traits> { let regions = (region SizedRegion<1>:$my_region); let assemblyFormat = "attr-dict `:` $my_region"; } def SingleNoTerminatorCustomAsmOp : TEST_Op<"single_no_terminator_custom_asm_op", [SingleBlock, NoTerminator]> { let regions = (region SizedRegion<1>); let hasCustomAssemblyFormat = 1; } def VariadicNoTerminatorOp : TEST_Op<"variadic_no_terminator_op", GraphRegionNoTerminator.traits> { let regions = (region VariadicRegion>:$my_regions); let assemblyFormat = "attr-dict `:` $my_regions"; } //===----------------------------------------------------------------------===// // Test Call Interfaces //===----------------------------------------------------------------------===// def TestCallOp : TEST_Op<"call", [DeclareOpInterfaceMethods]> { let arguments = (ins FlatSymbolRefAttr:$callee, Variadic:$operands); let results = (outs Variadic); let assemblyFormat = [{ $callee `(` $operands `)` attr-dict `:` functional-type($operands, results) }]; } def ConversionCallOp : TEST_Op<"conversion_call_op", [CallOpInterface]> { let arguments = (ins Variadic:$arg_operands, SymbolRefAttr:$callee); let results = (outs Variadic); let extraClassDeclaration = [{ /// Return the callee of this operation. ::mlir::CallInterfaceCallable getCallableForCallee(); }]; let extraClassDefinition = [{ ::mlir::CallInterfaceCallable $cppClass::getCallableForCallee() { return (*this)->getAttrOfType<::mlir::SymbolRefAttr>("callee"); } }]; } def FunctionalRegionOp : TEST_Op<"functional_region_op", [CallableOpInterface]> { let regions = (region AnyRegion:$body); let results = (outs FunctionType); let extraClassDeclaration = [{ ::mlir::Region *getCallableRegion() { return &getBody(); } ::llvm::ArrayRef<::mlir::Type> getCallableResults() { return getType().cast<::mlir::FunctionType>().getResults(); } }]; } def FoldToCallOp : TEST_Op<"fold_to_call_op"> { let arguments = (ins FlatSymbolRefAttr:$callee); let hasCanonicalizer = 1; } //===----------------------------------------------------------------------===// // Test Traits //===----------------------------------------------------------------------===// def SameOperandElementTypeOp : TEST_Op<"same_operand_element_type", [SameOperandsElementType]> { let arguments = (ins AnyType, AnyType); let results = (outs AnyType); } def SameOperandAndResultElementTypeOp : TEST_Op<"same_operand_and_result_element_type", [SameOperandsAndResultElementType]> { let arguments = (ins Variadic); let results = (outs Variadic); } def SameOperandShapeOp : TEST_Op<"same_operand_shape", [SameOperandsShape]> { let arguments = (ins Variadic); } def SameOperandAndResultShapeOp : TEST_Op<"same_operand_and_result_shape", [SameOperandsAndResultShape]> { let arguments = (ins Variadic); let results = (outs Variadic); } def SameOperandAndResultTypeOp : TEST_Op<"same_operand_and_result_type", [SameOperandsAndResultType]> { let arguments = (ins Variadic); let results = (outs Variadic); } def ElementwiseMappableOp : TEST_Op<"elementwise_mappable", ElementwiseMappable.traits> { let arguments = (ins Variadic); let results = (outs Variadic); } def ArgAndResHaveFixedElementTypesOp : TEST_Op<"arg_and_res_have_fixed_element_types", [PredOpTrait<"fixed type combination", And<[ElementTypeIsPred<"x", I32>, ElementTypeIsPred<"y", F32>]>>, ElementTypeIs<"res", I16>]> { let arguments = (ins AnyShaped:$x, AnyShaped:$y); let results = (outs AnyShaped:$res); } def OperandsHaveSameElementType : TEST_Op<"operands_have_same_element_type", [ AllElementTypesMatch<["x", "y"]>]> { let arguments = (ins AnyType:$x, AnyType:$y); } def OperandZeroAndResultHaveSameElementType : TEST_Op< "operand0_and_result_have_same_element_type", [AllElementTypesMatch<["x", "res"]>]> { let arguments = (ins AnyType:$x, AnyType:$y); let results = (outs AnyType:$res); } def OperandsHaveSameType : TEST_Op<"operands_have_same_type", [AllTypesMatch<["x", "y"]>]> { let arguments = (ins AnyType:$x, AnyType:$y); } def ResultHasSameTypeAsAttr : TEST_Op<"result_has_same_type_as_attr", [AllTypesMatch<["attr", "result"]>]> { let arguments = (ins AnyAttr:$attr); let results = (outs AnyType:$result); let assemblyFormat = "$attr `->` type($result) attr-dict"; } def OperandZeroAndResultHaveSameType : TEST_Op<"operand0_and_result_have_same_type", [AllTypesMatch<["x", "res"]>]> { let arguments = (ins AnyType:$x, AnyType:$y); let results = (outs AnyType:$res); } def OperandsHaveSameRank : TEST_Op<"operands_have_same_rank", [AllRanksMatch<["x", "y"]>]> { let arguments = (ins AnyShaped:$x, AnyShaped:$y); } def OperandZeroAndResultHaveSameRank : TEST_Op<"operand0_and_result_have_same_rank", [AllRanksMatch<["x", "res"]>]> { let arguments = (ins AnyShaped:$x, AnyShaped:$y); let results = (outs AnyShaped:$res); } def OperandZeroAndResultHaveSameShape : TEST_Op<"operand0_and_result_have_same_shape", [AllShapesMatch<["x", "res"]>]> { let arguments = (ins AnyShaped:$x, AnyShaped:$y); let results = (outs AnyShaped:$res); } def OperandZeroAndResultHaveSameElementCount : TEST_Op<"operand0_and_result_have_same_element_count", [AllElementCountsMatch<["x", "res"]>]> { let arguments = (ins AnyShaped:$x, AnyShaped:$y); let results = (outs AnyShaped:$res); } def FourEqualsFive : TEST_Op<"four_equals_five", [AllMatch<["5", "4"], "4 equals 5">]>; def OperandRankEqualsResultSize : TEST_Op<"operand_rank_equals_result_size", [AllMatch<[Rank<"operand">.result, ElementCount<"result">.result], "operand rank equals result size">]> { let arguments = (ins AnyShaped:$operand); let results = (outs AnyShaped:$result); } def IfFirstOperandIsNoneThenSoIsSecond : TEST_Op<"if_first_operand_is_none_then_so_is_second", [PredOpTrait< "has either both none type operands or first is not none", Or<[ And<[TypeIsPred<"x", NoneType>, TypeIsPred<"y", NoneType>]>, Neg>]>>]> { let arguments = (ins AnyType:$x, AnyType:$y); } def BroadcastableOp : TEST_Op<"broadcastable", [ResultsBroadcastableShape]> { let arguments = (ins Variadic); let results = (outs AnyTensor); } // HasParent trait def ParentOp : TEST_Op<"parent"> { let regions = (region AnyRegion); } def ChildOp : TEST_Op<"child", [HasParent<"ParentOp">]>; // ParentOneOf trait def ParentOp1 : TEST_Op<"parent1"> { let regions = (region AnyRegion); } def ChildWithParentOneOf : TEST_Op<"child_with_parent_one_of", [ParentOneOf<["ParentOp", "ParentOp1"]>]>; def TerminatorOp : TEST_Op<"finish", [Terminator]>; def SingleBlockImplicitTerminatorOp : TEST_Op<"SingleBlockImplicitTerminator", [SingleBlockImplicitTerminator<"TerminatorOp">]> { let regions = (region SizedRegion<1>:$region); } def I32ElementsAttrOp : TEST_Op<"i32ElementsAttr"> { let arguments = (ins I32ElementsAttr:$attr); } def IndexElementsAttrOp : TEST_Op<"indexElementsAttr"> { let arguments = (ins IndexElementsAttr:$attr); } def OpWithInferTypeInterfaceOp : TEST_Op<"op_with_infer_type_if", [ DeclareOpInterfaceMethods]> { let arguments = (ins AnyTensor, AnyTensor); let results = (outs AnyTensor); } def OpWithRefineTypeInterfaceOp : TEST_Op<"op_with_refine_type_if", [ DeclareOpInterfaceMethods]> { let arguments = (ins AnyTensor, AnyTensor); let results = (outs AnyTensor); } def OpWithShapedTypeInferTypeInterfaceOp : TEST_Op<"op_with_shaped_type_infer_type_if", [InferTensorTypeWithReify]> { let arguments = (ins AnyTensor, AnyTensor); let results = (outs AnyTensor); } def OpWithResultShapeInterfaceOp : TEST_Op<"op_with_result_shape_interface", [DeclareOpInterfaceMethods]> { let arguments = (ins AnyRankedTensor:$operand1, AnyRankedTensor:$operand2); let results = (outs AnyRankedTensor:$result1, AnyRankedTensor:$result2); } def OpWithResultShapePerDimInterfaceOp : TEST_Op<"op_with_result_shape_per_dim_interface", [DeclareOpInterfaceMethods]> { let arguments = (ins AnyRankedTensor:$operand1, AnyRankedTensor:$operand2); let results = (outs AnyRankedTensor:$result1, AnyRankedTensor:$result2); } def IsNotScalar : Constraint>; def UpdateAttr : Pat<(I32ElementsAttrOp $attr), (I32ElementsAttrOp ConstantAttr), [(IsNotScalar $attr)]>; def TestBranchOp : TEST_Op<"br", [DeclareOpInterfaceMethods, Terminator]> { let arguments = (ins Variadic:$targetOperands); let successors = (successor AnySuccessor:$target); } def TestProducingBranchOp : TEST_Op<"producing_br", [DeclareOpInterfaceMethods, Terminator, AttrSizedOperandSegments]> { let arguments = (ins Variadic:$firstOperands, Variadic:$secondOperands); let results = (outs I32:$dummy); let successors = (successor AnySuccessor:$first,AnySuccessor:$second); } // Produces an error value on the error path def TestInternalBranchOp : TEST_Op<"internal_br", [DeclareOpInterfaceMethods, Terminator, AttrSizedOperandSegments]> { let arguments = (ins Variadic:$successOperands, Variadic:$errorOperands); let successors = (successor AnySuccessor:$successPath, AnySuccessor:$errorPath); } def AttrSizedOperandOp : TEST_Op<"attr_sized_operands", [AttrSizedOperandSegments]> { let arguments = (ins Variadic:$a, Variadic:$b, I32:$c, Variadic:$d, I32ElementsAttr:$operand_segment_sizes ); } def AttrSizedResultOp : TEST_Op<"attr_sized_results", [AttrSizedResultSegments]> { let arguments = (ins I32ElementsAttr:$result_segment_sizes ); let results = (outs Variadic:$a, Variadic:$b, I32:$c, Variadic:$d ); } // 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 }]; } def OIListSimple : TEST_Op<"oilist_with_simple_args", [AttrSizedOperandSegments]> { let arguments = (ins Optional:$arg0, Optional:$arg1, Optional:$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:$arg0, Variadic:$arg1, Variadic:$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:$arg0, Optional:$optOperand, UnitAttr:$nowait); let assemblyFormat = [{ oilist( `private` `(` $arg0 `:` type($arg0) `)` | `reduction` custom($optOperand) | `nowait` $nowait ) attr-dict }]; } def OIListAllowedLiteral : TEST_Op<"oilist_allowed_literal"> { let assemblyFormat = [{ oilist( `foo` | `bar` ) `buzz` attr-dict }]; } // This is used to test encoding of a string attribute into an SSA name of a // pretty printed value name. def StringAttrPrettyNameOp : TEST_Op<"string_attr_pretty_name", [DeclareOpInterfaceMethods]> { let arguments = (ins StrArrayAttr:$names); let results = (outs Variadic:$r); let hasCustomAssemblyFormat = 1; } // This is used to test encoding of a string attribute into an SSA name of a // pretty printed value name. def CustomResultsNameOp : TEST_Op<"custom_result_name", [DeclareOpInterfaceMethods]> { let arguments = (ins Variadic:$optional, StrArrayAttr:$names ); let results = (outs Variadic:$r); } // This is used to test the OpAsmOpInterface::getDefaultDialect() feature: // operations nested in a region under this op will drop the "test." dialect // prefix. def DefaultDialectOp : TEST_Op<"default_dialect", [OpAsmOpInterface]> { let regions = (region AnyRegion:$body); let extraClassDeclaration = [{ static ::llvm::StringRef getDefaultDialect() { return "test"; } void getAsmResultNames(::llvm::function_ref setNameFn) {} }]; let assemblyFormat = "regions attr-dict-with-keyword"; } // 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"; } // This is used to test the OpAsmOpInterface::getAsmBlockName() feature: // blocks nested in a region under this op will have a name defined by the // interface. def AsmBlockNameOp : TEST_Op<"block_names", [OpAsmOpInterface]> { let regions = (region AnyRegion:$body); let extraClassDeclaration = [{ void getAsmBlockNames(mlir::OpAsmSetBlockNameFn setNameFn) { std::string name; int count = 0; for (::mlir::Block &block : getRegion().getBlocks()) { name = "foo" + std::to_string(count++); setNameFn(&block, name); } } }]; let assemblyFormat = "regions attr-dict-with-keyword"; } // This operation requires its return type to have the trait 'TestTypeTrait'. def ResultTypeWithTraitOp : TEST_Op<"result_type_with_trait", []> { let results = (outs AnyType); let hasVerifier = 1; } // This operation requires its "attr" attribute to have the // trait 'TestAttrTrait'. def AttrWithTraitOp : TEST_Op<"attr_with_trait", []> { let arguments = (ins AnyAttr:$attr); let hasVerifier = 1; } //===----------------------------------------------------------------------===// // Test Locations //===----------------------------------------------------------------------===// def TestLocationSrcOp : TEST_Op<"loc_src"> { let arguments = (ins I32:$input); let results = (outs I32:$output); } def TestLocationDstOp : TEST_Op<"loc_dst", [SameOperandsAndResultType]> { let arguments = (ins I32:$input); let results = (outs I32:$output); } def TestLocationSrcNoResOp : TEST_Op<"loc_src_no_res"> { let arguments = (ins I32:$input); let results = (outs); } def TestLocationDstNoResOp : TEST_Op<"loc_dst_no_res"> { let arguments = (ins I32:$input); let results = (outs); } //===----------------------------------------------------------------------===// // Test Patterns //===----------------------------------------------------------------------===// def OpA : TEST_Op<"op_a"> { let arguments = (ins I32, I32Attr:$attr); let results = (outs I32); } def OpB : TEST_Op<"op_b"> { let arguments = (ins I32, I32Attr:$attr); let results = (outs I32); } // Test named pattern. def TestNamedPatternRule : Pat<(OpA $input, $attr), (OpB $input, $attr)>; // Test with fused location. def : Pat<(OpA (OpA $input, $attr), $bttr), (OpB $input, $bttr)>; // Test added benefit. def OpD : TEST_Op<"op_d">, Arguments<(ins I32)>, Results<(outs I32)>; def OpE : TEST_Op<"op_e">, Arguments<(ins I32)>, Results<(outs I32)>; def OpF : TEST_Op<"op_f">, Arguments<(ins I32)>, Results<(outs I32)>; def OpG : TEST_Op<"op_g">, Arguments<(ins I32)>, Results<(outs I32)>; // Verify that bumping benefit results in selecting different op. def : Pat<(OpD $input), (OpE $input)>; def : Pat<(OpD $input), (OpF $input), [], (addBenefit 10)>; // Verify that patterns with more source nodes are selected before those with fewer. def : Pat<(OpG $input), (OpB $input, ConstantAttr:$attr)>; def : Pat<(OpG (OpG $input)), (OpB $input, ConstantAttr:$attr)>; // Test patterns for zero-result op. def OpH : TEST_Op<"op_h">, Arguments<(ins I32)>, Results<(outs)>; def OpI : TEST_Op<"op_i">, Arguments<(ins I32)>, Results<(outs)>; def : Pat<(OpH $input), (OpI $input)>; // Test patterns for zero-input op. def OpJ : TEST_Op<"op_j">, Arguments<(ins)>, Results<(outs I32)>; def OpK : TEST_Op<"op_k">, Arguments<(ins)>, Results<(outs I32)>; def : Pat<(OpJ), (OpK)>; // Test that natives calls are only called once during rewrites. def OpM : TEST_Op<"op_m"> { let arguments = (ins I32, OptionalAttr:$optional_attr); let results = (outs I32); } def OpN : TEST_Op<"op_n"> { let arguments = (ins I32, I32); let results = (outs I32); } def OpO : TEST_Op<"op_o"> { let arguments = (ins I32); let results = (outs I32); } def OpP : TEST_Op<"op_p"> { let arguments = (ins I32, I32, I32, I32, I32, I32); let results = (outs I32); } // Test same operand name enforces equality condition check. def TestEqualArgsPattern : Pat<(OpN $a, $a), (OpO $a)>; // Test when equality is enforced at different depth. def TestNestedOpEqualArgsPattern : Pat<(OpN $b, (OpP $a, $b, $c, $d, $e, $f)), (replaceWithValue $b)>; // Test when equality is enforced on same op and same operand but at different // depth. We only bound one of the $x to the second operand of outer OpN and // left another be the default value (which is the value of first operand of // outer OpN). As a result, it ended up comparing wrong values in some cases. def TestNestedSameOpAndSameArgEqualityPattern : Pat<(OpN (OpN $_, $x), $x), (replaceWithValue $x)>; // Test multiple equal arguments check enforced. def TestMultipleEqualArgsPattern : Pat<(OpP $a, $b, $a, $a, $b, $c), (OpN $c, $b)>; // Test for memrefs normalization of an op with normalizable memrefs. def OpNorm : TEST_Op<"op_norm", [MemRefsNormalizable]> { let arguments = (ins AnyMemRef:$X, AnyMemRef:$Y); } // Test for memrefs normalization of an op without normalizable memrefs. def OpNonNorm : TEST_Op<"op_nonnorm"> { let arguments = (ins AnyMemRef:$X, AnyMemRef:$Y); } // Test for memrefs normalization of an op that has normalizable memref results. def OpNormRet : TEST_Op<"op_norm_ret", [MemRefsNormalizable]> { let arguments = (ins AnyMemRef:$X); let results = (outs AnyMemRef:$Y, AnyMemRef:$Z); } // Test for memrefs normalization of an op with a reference to a function // symbol. def OpFuncRef : TEST_Op<"op_funcref"> { let summary = "Test op with a reference to a function symbol"; let description = [{ The "test.op_funcref" is a test op with a reference to a function symbol. }]; let builders = [OpBuilder<(ins "::mlir::func::FuncOp":$function)>]; } // Pattern add the argument plus a increasing static number hidden in // OpMTest function. That value is set into the optional argument. // That way, we will know if operations is called once or twice. def OpMGetNullAttr : NativeCodeCall<"Attribute()">; def OpMAttributeIsNull : Constraint, "Attribute is null">; def OpMVal : NativeCodeCall<"opMTest($_builder, $0)">; def : Pat<(OpM $attr, $optAttr), (OpM $attr, (OpMVal $attr) ), [(OpMAttributeIsNull:$optAttr)]>; // Test `$_` for ignoring op argument match. def TestIgnoreArgMatchSrcOp : TEST_Op<"ignore_arg_match_src"> { let arguments = (ins AnyType:$a, AnyType:$b, AnyType:$c, AnyAttr:$d, AnyAttr:$e, AnyAttr:$f); } def TestIgnoreArgMatchDstOp : TEST_Op<"ignore_arg_match_dst"> { let arguments = (ins AnyType:$b, AnyAttr:$f); } def : Pat<(TestIgnoreArgMatchSrcOp $_, $b, I32, I64Attr:$_, $_, $f), (TestIgnoreArgMatchDstOp $b, $f)>; def OpInterleavedOperandAttribute1 : TEST_Op<"interleaved_operand_attr1"> { let arguments = (ins I32:$input1, I64Attr:$attr1, I32:$input2, I64Attr:$attr2 ); } def OpInterleavedOperandAttribute2 : TEST_Op<"interleaved_operand_attr2"> { let arguments = (ins I32:$input1, I64Attr:$attr1, I32:$input2, I64Attr:$attr2 ); } def ManyArgsOp : TEST_Op<"many_arguments"> { let arguments = (ins I32:$input1, I32:$input2, I32:$input3, I32:$input4, I32:$input5, I32:$input6, I32:$input7, I32:$input8, I32:$input9, I64Attr:$attr1, I64Attr:$attr2, I64Attr:$attr3, I64Attr:$attr4, I64Attr:$attr5, I64Attr:$attr6, I64Attr:$attr7, I64Attr:$attr8, I64Attr:$attr9 ); } // Test that DRR does not blow up when seeing lots of arguments. def : Pat<(ManyArgsOp $input1, $input2, $input3, $input4, $input5, $input6, $input7, $input8, $input9, ConstantAttr, $attr2, $attr3, $attr4, $attr5, $attr6, $attr7, $attr8, $attr9), (ManyArgsOp $input1, $input2, $input3, $input4, $input5, $input6, $input7, $input8, $input9, ConstantAttr, $attr2, $attr3, $attr4, $attr5, $attr6, $attr7, $attr8, $attr9)>; // Test that we can capture and reference interleaved operands and attributes. def : Pat<(OpInterleavedOperandAttribute1 $input1, $attr1, $input2, $attr2), (OpInterleavedOperandAttribute2 $input1, $attr1, $input2, $attr2)>; // Test NativeCodeCall. def OpNativeCodeCall1 : TEST_Op<"native_code_call1"> { let arguments = (ins I32:$input1, I32:$input2, BoolAttr:$choice, I64Attr:$attr1, I64Attr:$attr2 ); let results = (outs I32); } def OpNativeCodeCall2 : TEST_Op<"native_code_call2"> { let arguments = (ins I32:$input, I64ArrayAttr:$attr); let results = (outs I32); } // Native code call to invoke a C++ function def CreateOperand: NativeCodeCall<"chooseOperand($0, $1, $2)">; // Native code call to invoke a C++ expression def CreateArrayAttr: NativeCodeCall<"$_builder.getArrayAttr({$0, $1})">; // Test that we can use NativeCodeCall to create operand and attribute. // This pattern chooses between $input1 and $input2 according to $choice and // it combines $attr1 and $attr2 into an array attribute. def : Pat<(OpNativeCodeCall1 $input1, $input2, ConstBoolAttrTrue:$choice, $attr1, $attr2), (OpNativeCodeCall2 (CreateOperand $input1, $input2, $choice), (CreateArrayAttr $attr1, $attr2))>; // Note: the following is just for testing purpose. // Should use the replaceWithValue directive instead. def UseOpResult: NativeCodeCall<"$0">; // Test that we can use NativeCodeCall to create result. def : Pat<(OpNativeCodeCall1 $input1, $input2, ConstBoolAttrFalse, $attr1, $attr2), (UseOpResult $input2)>; def OpNativeCodeCall3 : TEST_Op<"native_code_call3"> { let arguments = (ins I32:$input); let results = (outs I32); } // Test that NativeCodeCall is not ignored if it is not used to directly // replace the matched root op. def : Pattern<(OpNativeCodeCall3 $input), [(NativeCodeCallVoid<"createOpI($_builder, $_loc, $0)"> $input), (OpK)]>; def OpNativeCodeCall4 : TEST_Op<"native_code_call4"> { let arguments = (ins AnyType:$input1); let results = (outs I32:$output1, I32:$output2); } def OpNativeCodeCall5 : TEST_Op<"native_code_call5"> { let arguments = (ins I32:$input1, I32:$input2); let results = (outs I32:$output1, I32:$output2); } def GetFirstI32Result : NativeCodeCall<"success(getFirstI32Result($_self, $0))">; def BindNativeCodeCallResult : NativeCodeCall<"bindNativeCodeCallResult($0)">; def : Pat<(OpNativeCodeCall4 (GetFirstI32Result $ret)), (OpNativeCodeCall5 (BindNativeCodeCallResult:$native $ret), $native)>; def OpNativeCodeCall6 : TEST_Op<"native_code_call6"> { let arguments = (ins I32:$input1, I32:$input2); let results = (outs I32:$output1, I32:$output2); } def OpNativeCodeCall7 : TEST_Op<"native_code_call7"> { let arguments = (ins I32:$input); let results = (outs I32); } def BindMultipleNativeCodeCallResult : NativeCodeCall<"bindMultipleNativeCodeCallResult($0, $1)", 2>; def : Pattern<(OpNativeCodeCall6 $arg1, $arg2), [(OpNativeCodeCall7 (BindMultipleNativeCodeCallResult:$native__0 $arg1, $arg2)), (OpNativeCodeCall7 $native__1)]>; // Test AllAttrConstraintsOf. def OpAllAttrConstraint1 : TEST_Op<"all_attr_constraint_of1"> { let arguments = (ins I64ArrayAttr:$attr); let results = (outs I32); } def OpAllAttrConstraint2 : TEST_Op<"all_attr_constraint_of2"> { let arguments = (ins I64ArrayAttr:$attr); let results = (outs I32); } def Constraint0 : AttrConstraint< CPred<"$_self.cast()[0]." "cast<::mlir::IntegerAttr>().getInt() == 0">, "[0] == 0">; def Constraint1 : AttrConstraint< CPred<"$_self.cast()[1].cast<::mlir::IntegerAttr>().getInt() == 1">, "[1] == 1">; def : Pat<(OpAllAttrConstraint1 AllAttrConstraintsOf<[Constraint0, Constraint1]>:$attr), (OpAllAttrConstraint2 $attr)>; // Op for testing RewritePattern removing op with inner ops. def TestOpWithRegionPattern : TEST_Op<"op_with_region_pattern"> { let regions = (region SizedRegion<1>:$region); let hasCanonicalizer = 1; } def TestOpConstant : TEST_Op<"constant", [ConstantLike, NoSideEffect]> { let arguments = (ins AnyAttr:$value); let results = (outs AnyType); let hasFolder = 1; } def OpR : TEST_Op<"op_r">, Arguments<(ins AnyInteger, AnyInteger)>, Results<(outs AnyInteger)>; def OpS : TEST_Op<"op_s">, Arguments<(ins AnyInteger, AnyAttr:$value)>, Results<(outs AnyInteger)>; def : Pat<(OpR $input1, (ConstantLikeMatcher I32Attr:$input2)), (OpS:$unused $input1, $input2)>; // Op for testing trivial removal via folding of op with inner ops and no uses. def TestOpWithRegionFoldNoSideEffect : TEST_Op< "op_with_region_fold_no_side_effect", [NoSideEffect]> { let regions = (region SizedRegion<1>:$region); } // Op for testing folding of outer op with inner ops. def TestOpWithRegionFold : TEST_Op<"op_with_region_fold"> { let arguments = (ins I32:$operand); let results = (outs I32); let regions = (region SizedRegion<1>:$region); let hasFolder = 1; } def TestOpWithVariadicResultsAndFolder: TEST_Op<"op_with_variadic_results_and_folder"> { let arguments = (ins Variadic); let results = (outs Variadic); let hasFolder = 1; } def TestCommutativeOp : TEST_Op<"op_commutative", [Commutative]> { let arguments = (ins I32:$op1, I32:$op2, I32:$op3, I32:$op4); let results = (outs I32); } def TestCommutative2Op : TEST_Op<"op_commutative2", [Commutative]> { let arguments = (ins I32:$op1, I32:$op2); let results = (outs I32); } def TestIdempotentTraitOp : TEST_Op<"op_idempotent_trait", [SameOperandsAndResultType, NoSideEffect, Idempotent]> { let arguments = (ins I32:$op1); let results = (outs I32); } def TestIdempotentTraitBinaryOp : TEST_Op<"op_idempotent_trait_binary", [SameOperandsAndResultType, NoSideEffect, Idempotent]> { let arguments = (ins I32:$op1, I32:$op2); let results = (outs I32); } def TestInvolutionTraitNoOperationFolderOp : TEST_Op<"op_involution_trait_no_operation_fold", [SameOperandsAndResultType, NoSideEffect, Involution]> { let arguments = (ins I32:$op1); let results = (outs I32); } def TestInvolutionTraitFailingOperationFolderOp : TEST_Op<"op_involution_trait_failing_operation_fold", [SameOperandsAndResultType, NoSideEffect, Involution]> { let arguments = (ins I32:$op1); let results = (outs I32); let hasFolder = 1; } def TestInvolutionTraitSuccesfulOperationFolderOp : TEST_Op<"op_involution_trait_succesful_operation_fold", [SameOperandsAndResultType, NoSideEffect, Involution]> { let arguments = (ins I32:$op1); let results = (outs I32); let hasFolder = 1; } def TestOpInPlaceFoldAnchor : TEST_Op<"op_in_place_fold_anchor"> { let arguments = (ins I32); let results = (outs I32); } def TestOpInPlaceFold : TEST_Op<"op_in_place_fold"> { let arguments = (ins I32:$op, I32Attr:$attr); let results = (outs I32); let hasFolder = 1; } // Test op that simply returns success. def TestOpInPlaceFoldSuccess : TEST_Op<"op_in_place_fold_success"> { let results = (outs Variadic); let hasFolder = 1; let extraClassDefinition = [{ ::mlir::LogicalResult $cppClass::fold(ArrayRef operands, SmallVectorImpl &results) { return success(); } }]; } // An op that always fold itself. def TestPassthroughFold : TEST_Op<"passthrough_fold"> { let arguments = (ins AnyType:$op); let results = (outs AnyType); let hasFolder = 1; } def TestDialectCanonicalizerOp : TEST_Op<"dialect_canonicalizable"> { let arguments = (ins); let results = (outs I32); } //===----------------------------------------------------------------------===// // Test Patterns (Symbol Binding) // Test symbol binding. def OpSymbolBindingA : TEST_Op<"symbol_binding_a", []> { let arguments = (ins I32:$operand, I64Attr:$attr); let results = (outs I32); } def OpSymbolBindingB : TEST_Op<"symbol_binding_b", []> { let arguments = (ins I32:$operand); let results = (outs I32); } def OpSymbolBindingC : TEST_Op<"symbol_binding_c", []> { let arguments = (ins I32:$operand); let results = (outs I32); let builders = OpSymbolBindingB.builders; } def OpSymbolBindingD : TEST_Op<"symbol_binding_d", []> { let arguments = (ins I32:$input1, I32:$input2, I64Attr:$attr); let results = (outs I32); } def HasOneUse: Constraint, "has one use">; def : Pattern< // Bind to source pattern op operand/attribute/result (OpSymbolBindingA:$res_a $operand, $attr), [ // Bind to auxiliary op result (OpSymbolBindingC:$res_c (OpSymbolBindingB:$res_b $operand)), // Use bound symbols in resultant ops (OpSymbolBindingD $res_b, $res_c, $attr)], // Use bound symbols in additional constraints [(HasOneUse $res_a)]>; def OpSymbolBindingNoResult : TEST_Op<"symbol_binding_no_result", []> { let arguments = (ins I32:$operand); } // Test that we can bind to an op without results and reference it later. def : Pat<(OpSymbolBindingNoResult:$op $operand), (NativeCodeCallVoid<"handleNoResultOp($_builder, $0)"> $op)>; //===----------------------------------------------------------------------===// // Test Patterns (Attributes) // Test matching against op attributes. def OpAttrMatch1 : TEST_Op<"match_op_attribute1"> { let arguments = (ins I32Attr:$required_attr, OptionalAttr:$optional_attr, DefaultValuedAttr:$default_valued_attr, I32Attr:$more_attr ); let results = (outs I32); } def OpAttrMatch2 : TEST_Op<"match_op_attribute2"> { let arguments = OpAttrMatch1.arguments; let results = (outs I32); } def MoreConstraint : AttrConstraint< CPred<"$_self.cast().getInt() == 4">, "more constraint">; def : Pat<(OpAttrMatch1 $required, $optional, $default_valued, MoreConstraint:$more), (OpAttrMatch2 $required, $optional, $default_valued, $more)>; // Test unit attrs. def OpAttrMatch3 : TEST_Op<"match_op_attribute3"> { let arguments = (ins UnitAttr:$attr); let results = (outs I32); } def OpAttrMatch4 : TEST_Op<"match_op_attribute4"> { let arguments = (ins UnitAttr:$attr1, UnitAttr:$attr2); let results = (outs I32); } def : Pat<(OpAttrMatch3 $attr), (OpAttrMatch4 ConstUnitAttr, $attr)>; // Test with constant attr. def OpC : TEST_Op<"op_c">, Arguments<(ins I32)>, Results<(outs I32)>; def : Pat<(OpC $input), (OpB $input, ConstantAttr:$attr)>; // Test integer enum attribute in rewrites. def : Pat<(I32EnumAttrOp I32Case5), (I32EnumAttrOp I32Case10)>; def : Pat<(I64EnumAttrOp I64Case5), (I64EnumAttrOp I64Case10)>; //===----------------------------------------------------------------------===// // Test Patterns (Multi-result Ops) def MultiResultOpKind1: I64EnumAttrCase<"kind1", 1>; def MultiResultOpKind2: I64EnumAttrCase<"kind2", 2>; def MultiResultOpKind3: I64EnumAttrCase<"kind3", 3>; def MultiResultOpKind4: I64EnumAttrCase<"kind4", 4>; def MultiResultOpKind5: I64EnumAttrCase<"kind5", 5>; def MultiResultOpKind6: I64EnumAttrCase<"kind6", 6>; def MultiResultOpEnum: I64EnumAttr< "MultiResultOpEnum", "Multi-result op kinds", [ MultiResultOpKind1, MultiResultOpKind2, MultiResultOpKind3, MultiResultOpKind4, MultiResultOpKind5, MultiResultOpKind6 ]>; def ThreeResultOp : TEST_Op<"three_result"> { let arguments = (ins MultiResultOpEnum:$kind); let results = (outs I32:$result1, F32:$result2, F32:$result3); } def AnotherThreeResultOp : TEST_Op<"another_three_result", [DeclareOpInterfaceMethods]> { let arguments = (ins MultiResultOpEnum:$kind); let results = (outs I32:$result1, F32:$result2, F32:$result3); } def TwoResultOp : TEST_Op<"two_result"> { let arguments = (ins MultiResultOpEnum:$kind); let results = (outs I32:$result1, F32:$result2); } def AnotherTwoResultOp : TEST_Op<"another_two_result"> { let arguments = (ins MultiResultOpEnum:$kind); let results = (outs F32:$result1, F32:$result2); } def OneResultOp1 : TEST_Op<"one_result1"> { let arguments = (ins MultiResultOpEnum:$kind); let results = (outs F32:$result1); } def OneResultOp2 : TEST_Op<"one_result2"> { let arguments = (ins MultiResultOpEnum:$kind); let results = (outs I32:$result1); } def OneResultOp3 : TEST_Op<"one_result3"> { let arguments = (ins F32); let results = (outs I32:$result1); } // Test using multi-result op as a whole def : Pat<(ThreeResultOp MultiResultOpKind1:$kind), (AnotherThreeResultOp $kind)>; // Test using multi-result op as a whole for partial replacement def : Pattern<(ThreeResultOp MultiResultOpKind2:$kind), [(TwoResultOp $kind), (OneResultOp1 $kind)]>; def : Pattern<(ThreeResultOp MultiResultOpKind3:$kind), [(OneResultOp2 $kind), (AnotherTwoResultOp $kind)]>; // Test using results separately in a multi-result op def : Pattern<(ThreeResultOp MultiResultOpKind4:$kind), [(TwoResultOp:$res1__0 $kind), (OneResultOp1 $kind), (TwoResultOp:$res2__1 $kind)]>; // Test referencing a single value in the value pack // This rule only matches TwoResultOp if its second result has no use. def : Pattern<(TwoResultOp:$res MultiResultOpKind5:$kind), [(OneResultOp2 $kind), (OneResultOp1 $kind)], [(HasNoUseOf:$res__1)]>; // Test using auxiliary ops for replacing multi-result op def : Pattern< (ThreeResultOp MultiResultOpKind6:$kind), [ // Auxiliary op generated to help building the final result but not // directly used to replace the source op's results. (TwoResultOp:$interm $kind), (OneResultOp3 $interm__1), (AnotherTwoResultOp $kind) ]>; //===----------------------------------------------------------------------===// // Test Patterns (Variadic Ops) def OneVResOneVOperandOp1 : TEST_Op<"one_variadic_out_one_variadic_in1"> { let arguments = (ins Variadic); let results = (outs Variadic); } def OneVResOneVOperandOp2 : TEST_Op<"one_variadic_out_one_variadic_in2"> { let arguments = (ins Variadic); let results = (outs Variadic); } // Rewrite an op with one variadic operand and one variadic result to // another similar op. def : Pat<(OneVResOneVOperandOp1 $inputs), (OneVResOneVOperandOp2 $inputs)>; def MixedVOperandOp1 : TEST_Op<"mixed_variadic_in1", [SameVariadicOperandSize]> { let arguments = (ins Variadic:$input1, F32:$input2, Variadic:$input3 ); } def MixedVOperandOp2 : TEST_Op<"mixed_variadic_in2", [SameVariadicOperandSize]> { let arguments = (ins Variadic:$input1, F32:$input2, Variadic:$input3 ); } // Rewrite an op with both variadic operands and normal operands. def : Pat<(MixedVOperandOp1 $input1, $input2, $input3), (MixedVOperandOp2 $input1, $input2, $input3)>; def MixedVResultOp1 : TEST_Op<"mixed_variadic_out1", [SameVariadicResultSize]> { let results = (outs Variadic:$output1, F32:$output2, Variadic:$output3 ); } def MixedVResultOp2 : TEST_Op<"mixed_variadic_out2", [SameVariadicResultSize]> { let results = (outs Variadic:$output1, F32:$output2, Variadic:$output3 ); } // Rewrite an op with both variadic results and normal results. // Note that because we are generating the op with a top-level result pattern, // we are able to deduce the correct result types for the generated op using // the information from the matched root op. def : Pat<(MixedVResultOp1), (MixedVResultOp2)>; def OneI32ResultOp : TEST_Op<"one_i32_out"> { let results = (outs I32); } def MixedVOperandOp3 : TEST_Op<"mixed_variadic_in3", [SameVariadicOperandSize]> { let arguments = (ins I32:$input1, Variadic:$input2, Variadic:$input3, I32Attr:$count ); let results = (outs I32); } def MixedVResultOp3 : TEST_Op<"mixed_variadic_out3", [SameVariadicResultSize]> { let arguments = (ins I32Attr:$count); let results = (outs I32:$output1, Variadic:$output2, Variadic:$output3 ); // We will use this op in a nested result pattern, where we cannot deduce the // result type. So need to provide a builder not requiring result types. let builders = [ OpBuilder<(ins "::mlir::IntegerAttr":$count), [{ auto i32Type = $_builder.getIntegerType(32); $_state.addTypes(i32Type); // $output1 SmallVector types(count.getInt(), i32Type); $_state.addTypes(types); // $output2 $_state.addTypes(types); // $output3 $_state.addAttribute("count", count); }]> ]; } // Generates an op with variadic results using nested pattern. def : Pat<(OneI32ResultOp), (MixedVOperandOp3 (MixedVResultOp3:$results__0 ConstantAttr), (replaceWithValue $results__1), (replaceWithValue $results__2), ConstantAttr)>; //===----------------------------------------------------------------------===// // Test Patterns (either) def TestEitherOpA : TEST_Op<"either_op_a"> { let arguments = (ins AnyInteger:$arg0, AnyInteger:$arg1, AnyInteger:$arg2); let results = (outs I32:$output); } def TestEitherOpB : TEST_Op<"either_op_b"> { let arguments = (ins AnyInteger:$arg0); let results = (outs I32:$output); } def : Pat<(TestEitherOpA (either I32:$arg1, I16:$arg2), $_), (TestEitherOpB $arg2)>; def : Pat<(TestEitherOpA (either (TestEitherOpB I32:$arg1), I16:$arg2), $_), (TestEitherOpB $arg2)>; def : Pat<(TestEitherOpA (either (TestEitherOpB I32:$arg1), (TestEitherOpB I16:$arg2)), $_), (TestEitherOpB $arg2)>; //===----------------------------------------------------------------------===// // Test Patterns (Location) // Test that we can specify locations for generated ops. def : Pat<(TestLocationSrcOp:$res1 (TestLocationSrcOp:$res2 (TestLocationSrcOp:$res3 $input))), (TestLocationDstOp (TestLocationDstOp (TestLocationDstOp $input, (location $res1)), (location "named")), (location "fused", $res2, $res3))>; // Test that we can use the location of an op without results def : Pat<(TestLocationSrcNoResOp:$loc (TestLocationSrcOp (TestLocationSrcOp $input))), (TestLocationDstNoResOp $input, (location $loc))>; //===----------------------------------------------------------------------===// // Test Patterns (Type Builders) def SourceOp : TEST_Op<"source_op"> { let arguments = (ins AnyInteger:$arg, AnyI32Attr:$tag); let results = (outs AnyInteger); } // An op without return type deduction. def OpX : TEST_Op<"op_x"> { let arguments = (ins AnyInteger:$input); let results = (outs AnyInteger); } // Test that ops without built-in type deduction can be created in the // replacement DAG with an explicitly specified type. def : Pat<(SourceOp $val, ConstantAttr:$attr), (OpX (OpX $val, (returnType "$_builder.getI32Type()")))>; // Test NativeCodeCall type builder can accept arguments. def SameTypeAs : NativeCodeCall<"$0.getType()">; def : Pat<(SourceOp $val, ConstantAttr:$attr), (OpX (OpX $val, (returnType (SameTypeAs $val))))>; // Test multiple return types. def MakeI64Type : NativeCodeCall<"$_builder.getI64Type()">; def MakeI32Type : NativeCodeCall<"$_builder.getI32Type()">; def OneToTwo : TEST_Op<"one_to_two"> { let arguments = (ins AnyInteger); let results = (outs AnyInteger, AnyInteger); } def TwoToOne : TEST_Op<"two_to_one"> { let arguments = (ins AnyInteger, AnyInteger); let results = (outs AnyInteger); } def : Pat<(SourceOp $val, ConstantAttr:$attr), (TwoToOne (OpX (OneToTwo:$res__0 $val, (returnType (MakeI64Type), (MakeI32Type))), (returnType (MakeI32Type))), (OpX $res__1, (returnType (MakeI64Type))))>; // Test copy value return type. def : Pat<(SourceOp $val, ConstantAttr:$attr), (OpX (OpX $val, (returnType $val)))>; // Test create multiple return types with different methods. def : Pat<(SourceOp $val, ConstantAttr:$attr), (TwoToOne (OneToTwo:$res__0 $val, (returnType $val, "$_builder.getI64Type()")), $res__1)>; //===----------------------------------------------------------------------===// // Test Patterns (Trailing Directives) // Test that we can specify both `location` and `returnType` directives. def : Pat<(SourceOp $val, ConstantAttr:$attr), (TwoToOne (OpX $val, (returnType $val), (location "loc1")), (OpX $val, (location "loc2"), (returnType $val)))>; //===----------------------------------------------------------------------===// // Test Legalization //===----------------------------------------------------------------------===// def Test_LegalizerEnum_Success : ConstantStrAttr; def Test_LegalizerEnum_Failure : ConstantStrAttr; def ILLegalOpA : TEST_Op<"illegal_op_a">, Results<(outs I32)>; def ILLegalOpB : TEST_Op<"illegal_op_b">, Results<(outs I32)>; def ILLegalOpC : TEST_Op<"illegal_op_c">, Results<(outs I32)>; def ILLegalOpD : TEST_Op<"illegal_op_d">, Results<(outs I32)>; def ILLegalOpE : TEST_Op<"illegal_op_e">, Results<(outs I32)>; def ILLegalOpF : TEST_Op<"illegal_op_f">, Results<(outs I32)>; def ILLegalOpG : TEST_Op<"illegal_op_g">, Results<(outs I32)>; def LegalOpA : TEST_Op<"legal_op_a">, Arguments<(ins StrAttr:$status)>, Results<(outs I32)>; def LegalOpB : TEST_Op<"legal_op_b">, Results<(outs I32)>; def LegalOpC : TEST_Op<"legal_op_c">, Arguments<(ins I32)>, Results<(outs I32)>; // Check that the conversion infrastructure can properly undo the creation of // operations where an operation was created before its parent, in this case, // in the parent's builder. def IllegalOpTerminator : TEST_Op<"illegal_op_terminator", [Terminator]>; def IllegalOpWithRegion : TEST_Op<"illegal_op_with_region"> { let skipDefaultBuilders = 1; let builders = [OpBuilder<(ins), [{ Region *bodyRegion = $_state.addRegion(); OpBuilder::InsertionGuard g($_builder); Block *body = $_builder.createBlock(bodyRegion); $_builder.setInsertionPointToEnd(body); $_builder.create($_state.location); }]>]; } def IllegalOpWithRegionAnchor : TEST_Op<"illegal_op_with_region_anchor">; // Check that smaller pattern depths are chosen, i.e. prioritize more direct // mappings. def : Pat<(ILLegalOpA), (LegalOpA Test_LegalizerEnum_Success)>; def : Pat<(ILLegalOpA), (ILLegalOpB)>; def : Pat<(ILLegalOpB), (LegalOpA Test_LegalizerEnum_Failure)>; // Check that the higher benefit pattern is taken for multiple legalizations // with the same depth. def : Pat<(ILLegalOpC), (ILLegalOpD)>; def : Pat<(ILLegalOpD), (LegalOpA Test_LegalizerEnum_Failure)>; def : Pat<(ILLegalOpC), (ILLegalOpE), [], (addBenefit 10)>; def : Pat<(ILLegalOpE), (LegalOpA Test_LegalizerEnum_Success)>; // Check that patterns use the most up-to-date value when being replaced. def TestRewriteOp : TEST_Op<"rewrite">, Arguments<(ins AnyType)>, Results<(outs AnyType)>; def : Pat<(TestRewriteOp $input), (replaceWithValue $input)>; // Check that patterns can specify bounded recursion when rewriting. def TestRecursiveRewriteOp : TEST_Op<"recursive_rewrite"> { let arguments = (ins I64Attr:$depth); let assemblyFormat = "$depth attr-dict"; } // Test legalization pattern: this op will be erase and will also erase the // producer of its operand. def BlackHoleOp : TEST_Op<"blackhole">, Arguments<(ins AnyType)>; //===----------------------------------------------------------------------===// // Test Type Legalization //===----------------------------------------------------------------------===// def TestRegionBuilderOp : TEST_Op<"region_builder">; def TestReturnOp : TEST_Op<"return", [ReturnLike, Terminator]> { let arguments = (ins Variadic); let builders = [OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> ]; } def TestCastOp : TEST_Op<"cast">, Arguments<(ins Variadic)>, Results<(outs AnyType)>; def TestInvalidOp : TEST_Op<"invalid", [Terminator]>, Arguments<(ins Variadic)>; def TestTypeProducerOp : TEST_Op<"type_producer">, Results<(outs AnyType)>; def TestAnotherTypeProducerOp : TEST_Op<"another_type_producer">, Results<(outs AnyType)>; def TestTypeConsumerOp : TEST_Op<"type_consumer">, Arguments<(ins AnyType)>; def TestTypeChangerOp : TEST_Op<"type_changer">, Arguments<(ins AnyType)>, Results<(outs AnyType)>; def TestValidOp : TEST_Op<"valid", [Terminator]>, Arguments<(ins Variadic)>; def TestMergeBlocksOp : TEST_Op<"merge_blocks"> { let summary = "merge_blocks operation"; let description = [{ Test op with multiple blocks that are merged with Dialect Conversion }]; let regions = (region AnyRegion:$body); let results = (outs Variadic:$result); } def TestRemappedValueRegionOp : TEST_Op<"remapped_value_region", [SingleBlock]> { let summary = "remapped_value_region operation"; let description = [{ Test op that remaps values that haven't yet been converted in Dialect Conversion. }]; let regions = (region SizedRegion<1>:$body); let results = (outs Variadic:$result); } def TestSignatureConversionUndoOp : TEST_Op<"signature_conversion_undo"> { let regions = (region AnyRegion); } def TestSignatureConversionNoConverterOp : TEST_Op<"signature_conversion_no_converter"> { let regions = (region AnyRegion); } //===----------------------------------------------------------------------===// // Test parser. //===----------------------------------------------------------------------===// def ParseIntegerLiteralOp : TEST_Op<"parse_integer_literal"> { let results = (outs Variadic:$results); let hasCustomAssemblyFormat = 1; } def ParseWrappedKeywordOp : TEST_Op<"parse_wrapped_keyword"> { let arguments = (ins StrAttr:$keyword); let hasCustomAssemblyFormat = 1; } //===----------------------------------------------------------------------===// // Test region argument list parsing. def IsolatedRegionOp : TEST_Op<"isolated_region", [IsolatedFromAbove]> { let summary = "isolated region operation"; let description = [{ Test op with an isolated region, to test passthrough region arguments. Each argument is of index type. }]; let arguments = (ins Index); let regions = (region SizedRegion<1>:$region); let hasCustomAssemblyFormat = 1; } def SSACFGRegionOp : TEST_Op<"ssacfg_region", [ DeclareOpInterfaceMethods]> { let summary = "operation with an SSACFG region"; let description = [{ Test op that defines an SSACFG region. }]; let regions = (region VariadicRegion:$regions); let arguments = (ins Variadic); let results = (outs Variadic); } def GraphRegionOp : TEST_Op<"graph_region", [ DeclareOpInterfaceMethods]> { let summary = "operation with a graph region"; let description = [{ Test op that defines a graph region. }]; let regions = (region AnyRegion:$region); let assemblyFormat = "attr-dict-with-keyword $region"; } def AffineScopeOp : TEST_Op<"affine_scope", [AffineScope]> { let summary = "affine scope operation"; let description = [{ Test op that defines a new affine scope. }]; let regions = (region SizedRegion<1>:$region); let hasCustomAssemblyFormat = 1; } 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); 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 ®ion, mlir::OpAsmSetValueNameFn setNameFn); }]; let regions = (region SizedRegion<1>:$region); let hasCustomAssemblyFormat = 1; } //===----------------------------------------------------------------------===// // Test OpAsmInterface. def AsmInterfaceOp : TEST_Op<"asm_interface_op"> { let results = (outs AnyType:$first, Variadic:$middle_results, AnyType); } def AsmDialectInterfaceOp : TEST_Op<"asm_dialect_interface_op"> { let results = (outs AnyType); } //===----------------------------------------------------------------------===// // 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:$opt_attr); let assemblyFormat = "(`(` $opt_attr^ `)` )? attr-dict"; } def FormatOptAttrBOp : TEST_Op<"format_opt_attr_op_b"> { let arguments = (ins OptionalAttr:$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:$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:$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 : 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 : TEST_Op<"format_variadic_region_" # suffix # "_op"> { let regions = (region VariadicRegion:$regions); let assemblyFormat = fmt; } def FormatVariadicRegionAOp : FormatVariadicRegionBase<"a", [{ $regions attr-dict }]>; def FormatVariadicRegionBOp : FormatVariadicRegionBase<"b", [{ ($regions^ `found_regions`)? attr-dict }]>; class FormatRegionImplicitTerminatorBase : 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 : 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:$result); let assemblyFormat = [{ `:` type($result) attr-dict}]; } def FormatMultipleVariadicResults : TEST_Op<"format_multiple_variadic_results", [AttrSizedResultSegments]> { let results = (outs Variadic:$result0, Variadic:$result1); let assemblyFormat = [{ `:` `(` type($result0) `)` `,` `(` type($result1) `)` attr-dict }]; } // Test various mixings of operand type formatting. class FormatOperandBase : 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:$targets); let assemblyFormat = "$targets attr-dict"; } def FormatVariadicOperand : TEST_Op<"format_variadic_operand"> { let arguments = (ins Variadic:$operand); let assemblyFormat = [{ $operand `:` type($operand) attr-dict}]; } def FormatVariadicOfVariadicOperand : TEST_Op<"format_variadic_of_variadic_operand"> { let arguments = (ins VariadicOfVariadic:$operand, I32ElementsAttr:$operand_segments ); let assemblyFormat = [{ $operand `:` type($operand) attr-dict}]; } def FormatMultipleVariadicOperands : TEST_Op<"format_multiple_variadic_operands", [AttrSizedOperandSegments]> { let arguments = (ins Variadic:$operand0, Variadic:$operand1); let assemblyFormat = [{ ` ` `(` $operand0 `)` `,` `(` $operand1 `:` type($operand1) `)` attr-dict }]; } // Test various mixings of optional operand and result type formatting. class FormatOptionalOperandResultOpBase : TEST_Op<"format_optional_operand_result_" # suffix # "_op", [AttrSizedOperandSegments]> { let arguments = (ins Optional:$optional, Variadic:$variadic); let results = (outs Optional:$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 : TEST_Op<"format_optional_result_" # suffix # "_op", [AttrSizedResultSegments]> { let results = (outs Optional:$optional, Variadic:$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:$optional); let assemblyFormat = "(`:` type($optional)^)? attr-dict"; } def FormatTwoVariadicOperandsNoBuildableTypeOp : TEST_Op<"format_two_variadic_operands_no_buildable_type_op", [AttrSizedOperandSegments]> { let arguments = (ins Variadic:$a, Variadic:$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:$args); let results = (outs AnyType:$result); let assemblyFormat = "$args 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 FormatOptionalEnumAttr : TEST_Op<"format_optional_enum_attr"> { let arguments = (ins OptionalAttr:$attr); let assemblyFormat = "($attr^)? 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 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:$optOperand, Variadic:$varOperands); let assemblyFormat = [{ custom( $operand, $optOperand, $varOperands ) attr-dict }]; } def FormatCustomDirectiveOperandsAndTypes : TEST_Op<"format_custom_directive_operands_and_types", [AttrSizedOperandSegments]> { let arguments = (ins AnyType:$operand, Optional:$optOperand, Variadic:$varOperands); let assemblyFormat = [{ custom( $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:$other_regions); let assemblyFormat = [{ custom( $region, $other_regions ) attr-dict }]; } def FormatCustomDirectiveResults : TEST_Op<"format_custom_directive_results", [AttrSizedResultSegments]> { let results = (outs AnyType:$result, Optional:$optResult, Variadic:$varResults); let assemblyFormat = [{ custom( 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:$optResult, Variadic:$varResults); let assemblyFormat = [{ custom( type($result), type($optResult), type($varResults) ) custom( 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:$optOperand); let assemblyFormat = [{ ($optOperand^)? `:` custom(ref($optOperand)) attr-dict }]; } def FormatCustomDirectiveSuccessors : TEST_Op<"format_custom_directive_successors", [Terminator]> { let successors = (successor AnySuccessor:$successor, VariadicSuccessor:$successors); let assemblyFormat = [{ custom( $successor, $successors ) attr-dict }]; } def FormatCustomDirectiveAttributes : TEST_Op<"format_custom_directive_attributes"> { let arguments = (ins I64Attr:$attr, OptionalAttr:$optAttr); let assemblyFormat = [{ custom( $attr, $optAttr ) attr-dict }]; } def FormatCustomDirectiveAttrDict : TEST_Op<"format_custom_directive_attrdict"> { let arguments = (ins I64Attr:$attr, OptionalAttr:$optAttr); let assemblyFormat = [{ custom( attr-dict ) }]; } def FormatLiteralFollowingOptionalGroup : TEST_Op<"format_literal_following_optional_group"> { let arguments = (ins TypeAttr:$type, OptionalAttr:$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 AnyAttr:$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:$value); let results = (outs Variadic:$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 AnyAttr:$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 ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::llvm::Optional<::mlir::Location> location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::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]> { let results = (outs AnyType); let assemblyFormat = "attr-dict"; } // Base class for testing mixing allOperandTypes, allOperands, and // inferResultTypes. class FormatInferAllTypesBaseOp traits = []> : TEST_Op { let arguments = (ins Variadic:$args); let results = (outs Variadic:$outs); let extraClassDeclaration = [{ static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::llvm::Optional<::mlir::Location> location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::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:$args0, Variadic:$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:$outs); let regions = (region AnyRegion:$region); let assemblyFormat = "$region attr-dict"; let extraClassDeclaration = [{ static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::llvm::Optional<::mlir::Location> location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::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 (operand_segment_sizes). def FormatInferTypeVariadicOperandsOp : TEST_Op<"format_infer_type_variadic_operands", [InferTypeOpInterface, AttrSizedOperandSegments]> { let arguments = (ins Variadic:$a, Variadic:$b); let results = (outs Variadic:$outs); let assemblyFormat = "`(` $a `:` type($a) `)` `(` $b `:` type($b) `)` attr-dict"; let extraClassDeclaration = [{ static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::llvm::Optional<::mlir::Location> location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions, ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) { FormatInferTypeVariadicOperandsOpAdaptor adaptor(operands, attributes); 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(); } }]; } //===----------------------------------------------------------------------===// // Test SideEffects //===----------------------------------------------------------------------===// def SideEffectOp : TEST_Op<"side_effect_op", [DeclareOpInterfaceMethods, DeclareOpInterfaceMethods]> { let results = (outs AnyType:$result); } //===----------------------------------------------------------------------===// // Test CopyOpInterface //===----------------------------------------------------------------------===// def CopyOp : TEST_Op<"copy", [CopyOpInterface]> { let description = [{ Represents a copy operation. }]; let arguments = (ins Res:$source, Res:$target); let assemblyFormat = [{ `(` $source `,` $target `)` `:` `(` type($source) `,` type($target) `)` attr-dict }]; } //===----------------------------------------------------------------------===// // Test Buffer/Tensor //===----------------------------------------------------------------------===// def RegionYieldOp : TEST_Op<"region_yield", [NoSideEffect, ReturnLike, Terminator]> { let description = [{ This operation is used in a region and yields the corresponding type for that operation. }]; let arguments = (ins AnyType:$result); let assemblyFormat = [{ $result `:` type($result) attr-dict }]; let builders = [OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> ]; } class BufferBasedOpBase traits> : TEST_Op { let description = [{ A buffer based operation, that uses memRefs as input and output. }]; let arguments = (ins AnyRankedOrUnrankedMemRef:$input, AnyRankedOrUnrankedMemRef:$output); } def BufferBasedOp : BufferBasedOpBase<"buffer_based", []>{ let assemblyFormat = [{ `in` `(` $input`:` type($input) `)` `out` `(` $output`:` type($output) `)` attr-dict }]; } def RegionBufferBasedOp : BufferBasedOpBase<"region_buffer_based", [SingleBlockImplicitTerminator<"RegionYieldOp">]> { let regions = (region AnyRegion:$region); let assemblyFormat = [{ `in` `(` $input`:` type($input) `)` `out` `(` $output`:` type($output) `)` $region attr-dict }]; } def TensorBasedOp : TEST_Op<"tensor_based", []> { let description = [{ A tensor based operation, that uses a tensor as an input and results in a tensor again. }]; let arguments = (ins AnyRankedTensor:$input); let results = (outs AnyRankedTensor:$result); let assemblyFormat = [{ `in` `(` $input`:` type($input) `)` `->` type($result) attr-dict }]; } //===----------------------------------------------------------------------===// // Test RegionBranchOpInterface //===----------------------------------------------------------------------===// def RegionIfYieldOp : TEST_Op<"region_if_yield", [NoSideEffect, ReturnLike, Terminator]> { let arguments = (ins Variadic:$results); let assemblyFormat = [{ $results `:` type($results) attr-dict }]; } def RegionIfOp : TEST_Op<"region_if", [DeclareOpInterfaceMethods, SingleBlockImplicitTerminator<"RegionIfYieldOp">, RecursiveSideEffects]> { let description =[{ Represents an abstract if-then-else-join pattern. In this context, the then and else regions jump to the join region, which finally returns to its parent op. }]; let arguments = (ins Variadic); let results = (outs Variadic:$results); let regions = (region SizedRegion<1>:$thenRegion, AnyRegion:$elseRegion, AnyRegion:$joinRegion); let extraClassDeclaration = [{ ::mlir::Block::BlockArgListType getThenArgs() { return getBody(0)->getArguments(); } ::mlir::Block::BlockArgListType getElseArgs() { return getBody(1)->getArguments(); } ::mlir::Block::BlockArgListType getJoinArgs() { return getBody(2)->getArguments(); } ::mlir::OperandRange getSuccessorEntryOperands( ::llvm::Optional index); }]; let hasCustomAssemblyFormat = 1; } def AnyCondOp : TEST_Op<"any_cond", [DeclareOpInterfaceMethods, RecursiveSideEffects]> { let results = (outs Variadic:$results); let regions = (region AnyRegion:$region); } //===----------------------------------------------------------------------===// // Test TableGen generated build() methods //===----------------------------------------------------------------------===// def TableGenConstant : TEST_Op<"tblgen_constant"> { let results = (outs AnyType); } // No variadic args or results. def TableGenBuildOp0 : TEST_Op<"tblgen_build_0"> { let arguments = (ins AnyType:$value); let results = (outs AnyType:$result); } // Sigle variadic arg and single variadic results. def TableGenBuildOp1 : TEST_Op<"tblgen_build_1"> { let arguments = (ins Variadic:$inputs); let results = (outs Variadic:$results); } // Single variadic arg and non-variadic results. def TableGenBuildOp2 : TEST_Op<"tblgen_build_2"> { let arguments = (ins Variadic:$inputs); let results = (outs AnyType:$result); } // Single variadic arg and multiple variadic results. def TableGenBuildOp3 : TEST_Op<"tblgen_build_3", [SameVariadicResultSize]> { let arguments = (ins Variadic:$inputs); let results = (outs Variadic:$resultA, Variadic:$resultB); } // Single variadic arg, non variadic results, with SameOperandsAndResultType. // Tests suppression of ambiguous build methods for operations with // SameOperandsAndResultType trait. def TableGenBuildOp4 : TEST_Op<"tblgen_build_4", [SameOperandsAndResultType]> { let arguments = (ins Variadic:$inputs); let results = (outs AnyType:$result); } // Base class for testing `build` methods for ops with // InferReturnTypeOpInterface. class TableGenBuildInferReturnTypeBaseOp traits = []> : TEST_Op { let arguments = (ins Variadic:$inputs); let results = (outs AnyType:$result); let extraClassDeclaration = [{ static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *, ::llvm::Optional<::mlir::Location> location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions, ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) { inferredReturnTypes.assign({operands[0].getType()}); return ::mlir::success(); } }]; } // Op with InferTypeOpInterface and regions. def TableGenBuildOp5 : TableGenBuildInferReturnTypeBaseOp< "tblgen_build_5", [InferTypeOpInterface]> { let regions = (region AnyRegion:$body); } //===----------------------------------------------------------------------===// // Test BufferPlacement //===----------------------------------------------------------------------===// def GetTupleElementOp: TEST_Op<"get_tuple_element"> { let description = [{ Test op that returns a specified element of the tuple. }]; let arguments = (ins TupleOf<[AnyType]>, I32Attr:$index ); let results = (outs AnyType); } def MakeTupleOp: TEST_Op<"make_tuple"> { let description = [{ Test op that creates a tuple value from a list of values. }]; let arguments = (ins Variadic:$inputs ); let results = (outs TupleOf<[AnyType]>); } //===----------------------------------------------------------------------===// // Test Target DataLayout //===----------------------------------------------------------------------===// def OpWithDataLayoutOp : TEST_Op<"op_with_data_layout", [HasDefaultDLTIDataLayout, DataLayoutOpInterface]> { let summary = "An op that uses DataLayout implementation from the Target dialect"; let regions = (region VariadicRegion:$regions); } def DataLayoutQueryOp : TEST_Op<"data_layout_query"> { let summary = "A token op recognized by data layout query test pass"; let description = [{ The data layout query pass pattern-matches this op and attaches to it an array attribute containing the result of data layout query of the result type of this op. }]; let results = (outs AnyType:$res); } //===----------------------------------------------------------------------===// // Test Reducer Patterns //===----------------------------------------------------------------------===// def OpCrashLong : TEST_Op<"op_crash_long"> { let arguments = (ins I32, I32, I32); let results = (outs I32); } def OpCrashShort : TEST_Op<"op_crash_short"> { let results = (outs I32); } def : Pat<(OpCrashLong $_, $_, $_), (OpCrashShort)>; //===----------------------------------------------------------------------===// // Test LinalgConvolutionOpInterface. //===----------------------------------------------------------------------===// def TestLinalgConvOpNotLinalgOp : TEST_Op<"conv_op_not_linalg_op", [ LinalgConvolutionOpInterface]> { let arguments = (ins AnyType:$image, AnyType:$filter, AnyType:$output); let results = (outs AnyRankedTensor:$result); } def TestLinalgConvOp : TEST_Op<"linalg_conv_op", [AttrSizedOperandSegments, SingleBlock, LinalgStructuredInterface, LinalgConvolutionOpInterface]> { let arguments = (ins Variadic:$inputs, Variadic:$outputs); let results = (outs Variadic:$results); let regions = (region AnyRegion:$region); let assemblyFormat = [{ attr-dict (`ins` `(` $inputs^ `:` type($inputs) `)`)? `outs` `(` $outputs `:` type($outputs) `)` $region (`->` type($results)^)? }]; let extraClassDeclaration = [{ bool hasIndexSemantics() { return false; } static void regionBuilder(mlir::ImplicitLocOpBuilder &b, mlir::Block &block, mlir::ArrayRef attrs) { b.create(block.getArguments().back()); } static std::function)> getRegionBuilder() { return ®ionBuilder; } mlir::ArrayAttr iterator_types() { return getOperation()->getAttrOfType("iterator_types"); } mlir::ArrayAttr getIndexingMaps() { return getOperation()->getAttrOfType("indexing_maps"); } std::string getLibraryCallName() { return ""; } // To conform with interface requirement on operand naming. mlir::ValueRange inputs() { return getInputs(); } mlir::ValueRange outputs() { return getOutputs(); } }]; } //===----------------------------------------------------------------------===// // Test LinalgFillOpInterface. //===----------------------------------------------------------------------===// def TestLinalgFillOpNotLinalgOp : TEST_Op<"fill_op_not_linalg_op", [ LinalgFillOpInterface]> { let arguments = (ins AnyType:$value, AnyType:$output); let results = (outs AnyRankedTensor:$result); } def TestLinalgFillOp : TEST_Op<"linalg_fill_op", [AttrSizedOperandSegments, SingleBlock, LinalgStructuredInterface, LinalgFillOpInterface]> { let arguments = (ins Variadic:$inputs, Variadic:$outputs); let results = (outs Variadic:$results); let regions = (region AnyRegion:$region); let assemblyFormat = [{ attr-dict (`ins` `(` $inputs^ `:` type($inputs) `)`)? `outs` `(` $outputs `:` type($outputs) `)` $region (`->` type($results)^)? }]; let extraClassDeclaration = [{ bool hasIndexSemantics() { return false; } static void regionBuilder(mlir::ImplicitLocOpBuilder &b, mlir::Block &block, mlir::ArrayRef attrs) { b.create(block.getArguments().back()); } static std::function)> getRegionBuilder() { return ®ionBuilder; } mlir::ArrayAttr iterator_types() { return getOperation()->getAttrOfType("iterator_types"); } mlir::ArrayAttr getIndexingMaps() { return getOperation()->getAttrOfType("indexing_maps"); } std::string getLibraryCallName() { return ""; } // To conform with interface requirement on operand naming. mlir::ValueRange inputs() { return getInputs(); } mlir::ValueRange outputs() { return getOutputs(); } }]; } //===----------------------------------------------------------------------===// // Test Ops with Default-Valued String Attributes //===----------------------------------------------------------------------===// def TestDefaultStrAttrNoValueOp : TEST_Op<"no_str_value"> { let arguments = (ins DefaultValuedAttr:$value); let assemblyFormat = "attr-dict"; } def TestDefaultStrAttrHasValueOp : TEST_Op<"has_str_value"> { let arguments = (ins DefaultValuedStrAttr:$value); let assemblyFormat = "attr-dict"; } def : Pat<(TestDefaultStrAttrNoValueOp $value), (TestDefaultStrAttrHasValueOp ConstantStrAttr)>; //===----------------------------------------------------------------------===// // Test Ops with effects //===----------------------------------------------------------------------===// def TestResource : Resource<"TestResource">; def TestEffectsOpA : TEST_Op<"op_with_effects_a"> { let arguments = (ins Arg, "", [MemRead]>, Arg:$first, Arg:$second, Arg, "", [MemRead]>:$optional_symbol ); let results = (outs Res]>); } def TestEffectsOpB : TEST_Op<"op_with_effects_b", [MemoryEffects<[MemWrite]>]>; def TestEffectsRead : TEST_Op<"op_with_memread", [MemoryEffects<[MemRead]>]> { let results = (outs AnyInteger); } def TestEffectsWrite : TEST_Op<"op_with_memwrite", [MemoryEffects<[MemWrite]>]>; def TestEffectsResult : TEST_Op<"test_effects_result"> { let results = (outs Res); } //===----------------------------------------------------------------------===// // Test Ops with verifiers //===----------------------------------------------------------------------===// def TestVerifiersOp : TEST_Op<"verifiers", [SingleBlock, NoTerminator, IsolatedFromAbove]> { let arguments = (ins I32:$input); let regions = (region SizedRegion<1>:$region); let hasVerifier = 1; let hasRegionVerifier = 1; } //===----------------------------------------------------------------------===// // Test Loop Op with a graph region //===----------------------------------------------------------------------===// // Test loop op with a graph region. def TestGraphLoopOp : TEST_Op<"graph_loop", [LoopLikeOpInterface, NoSideEffect, RecursiveSideEffects, SingleBlock, RegionKindInterface, HasOnlyGraphRegion]> { let arguments = (ins Variadic:$args); let results = (outs Variadic:$rets); let regions = (region SizedRegion<1>:$body); let assemblyFormat = [{ $args $body attr-dict `:` functional-type(operands, results) }]; let extraClassDeclaration = [{ mlir::Region &getLoopBody() { return getBody(); } }]; } //===----------------------------------------------------------------------===// // Test InferIntRangeInterface //===----------------------------------------------------------------------===// def TestWithBoundsOp : TEST_Op<"with_bounds", [DeclareOpInterfaceMethods, NoSideEffect]> { let arguments = (ins IndexAttr:$umin, IndexAttr:$umax, IndexAttr:$smin, IndexAttr:$smax); let results = (outs Index:$fakeVal); let assemblyFormat = "attr-dict"; } def TestWithBoundsRegionOp : TEST_Op<"with_bounds_region", [DeclareOpInterfaceMethods, SingleBlock, NoTerminator]> { let arguments = (ins IndexAttr:$umin, IndexAttr:$umax, IndexAttr:$smin, IndexAttr:$smax); // The region has one argument of index type let regions = (region SizedRegion<1>:$region); let hasCustomAssemblyFormat = 1; } def TestIncrementOp : TEST_Op<"increment", [DeclareOpInterfaceMethods, NoSideEffect]> { let arguments = (ins Index:$value); let results = (outs Index:$result); let assemblyFormat = "attr-dict $value"; } def TestReflectBoundsOp : TEST_Op<"reflect_bounds", [DeclareOpInterfaceMethods]> { let arguments = (ins Index:$value, OptionalAttr:$umin, OptionalAttr:$umax, OptionalAttr:$smin, OptionalAttr:$smax); let results = (outs Index:$result); let assemblyFormat = "attr-dict $value"; } #endif // TEST_OPS