1//===- Ops.td - Toy dialect operation definitions ----------*- tablegen -*-===// 2// 3// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// Defines the operations of the Toy dialect. 10// 11//===----------------------------------------------------------------------===// 12 13#ifndef TOY_OPS 14#define TOY_OPS 15 16include "mlir/IR/OpBase.td" 17 18// Provide a definition of the 'toy' dialect in the ODS framework so that we 19// can define our operations. 20def Toy_Dialect : Dialect { 21 let name = "toy"; 22 let cppNamespace = "toy"; 23} 24 25// Base class for toy dialect operations. This operation inherits from the base 26// `Op` class in OpBase.td, and provides: 27// * The parent dialect of the operation. 28// * The mnemonic for the operation, or the name without the dialect prefix. 29// * A list of traits for the operation. 30class Toy_Op<string mnemonic, list<OpTrait> traits = []> : 31 Op<Toy_Dialect, mnemonic, traits>; 32 33//===----------------------------------------------------------------------===// 34// Toy Operations 35//===----------------------------------------------------------------------===// 36 37// We define a toy operation by inheriting from our base 'Toy_Op' class above. 38// Here we provide the mnemonic and a list of traits for the operation. The 39// constant operation is marked as 'NoSideEffect' as it is a pure operation 40// and may be removed if dead. 41def ConstantOp : Toy_Op<"constant", [NoSideEffect]> { 42 // Provide a summary and description for this operation. This can be used to 43 // auto-generate documentation of the operations within our dialect. 44 let summary = "constant"; 45 let description = [{ 46 Constant operation turns a literal into an SSA value. The data is attached 47 to the operation as an attribute. For example: 48 49 ```mlir 50 %0 = "toy.constant"() 51 { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } 52 : () -> tensor<2x3xf64> 53 ``` 54 }]; 55 56 // The constant operation takes an attribute as the only input. 57 let arguments = (ins F64ElementsAttr:$value); 58 59 // The constant operation returns a single value of TensorType. 60 let results = (outs F64Tensor); 61 62 // Add custom build methods for the constant operation. These method populates 63 // the `state` that MLIR uses to create operations, i.e. these are used when 64 // using `builder.create<ConstantOp>(...)`. 65 let builders = [ 66 // Build a constant with a given constant tensor value. 67 OpBuilder<"Builder *builder, OperationState &state, " 68 "DenseElementsAttr value", [{ 69 build(builder, state, value.getType(), value); 70 }]>, 71 72 // Build a constant with a given constant floating-point value. 73 OpBuilder<"Builder *builder, OperationState &state, double value"> 74 ]; 75 76 // Invoke a static verify method to verify this constant operation. 77 let verifier = [{ return ::verify(*this); }]; 78} 79 80def AddOp : Toy_Op<"add", [NoSideEffect]> { 81 let summary = "element-wise addition operation"; 82 let description = [{ 83 The "add" operation performs element-wise addition between two tensors. 84 The shapes of the tensor operands are expected to match. 85 }]; 86 87 let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); 88 let results = (outs F64Tensor); 89 90 // Allow building an AddOp with from the two input operands. 91 let builders = [ 92 OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> 93 ]; 94} 95 96def GenericCallOp : Toy_Op<"generic_call"> { 97 let summary = "generic call operation"; 98 let description = [{ 99 Generic calls represent calls to a user defined function that needs to 100 be specialized for the shape of its arguments. The callee name is attached 101 as a symbol reference via an attribute. The arguments list must match the 102 arguments expected by the callee. For example: 103 104 ```mlir 105 %4 = "toy.generic_call"(%1, %3) {callee = @my_func} 106 : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> 107 ``` 108 109 This is only valid if a function named "my_func" exists and takes two 110 arguments. 111 }]; 112 113 // The generic call operation takes a symbol reference attribute as the 114 // callee, and inputs for the call. 115 let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<F64Tensor>:$inputs); 116 117 // The generic call operation returns a single value of TensorType. 118 let results = (outs F64Tensor); 119 120 // Add custom build methods for the generic call operation. 121 let builders = [ 122 OpBuilder<"Builder *builder, OperationState &state, " 123 "StringRef callee, ArrayRef<Value> arguments"> 124 ]; 125} 126 127def MulOp : Toy_Op<"mul", [NoSideEffect]> { 128 let summary = "element-wise multiplication operation"; 129 let description = [{ 130 The "mul" operation performs element-wise multiplication between two 131 tensors. The shapes of the tensor operands are expected to match. 132 }]; 133 134 let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); 135 let results = (outs F64Tensor); 136 137 // Allow building a MulOp with from the two input operands. 138 let builders = [ 139 OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> 140 ]; 141} 142 143def PrintOp : Toy_Op<"print"> { 144 let summary = "print operation"; 145 let description = [{ 146 The "print" builtin operation prints a given input tensor, and produces 147 no results. 148 }]; 149 150 // The print operation takes an input tensor to print. 151 let arguments = (ins F64Tensor:$input); 152} 153 154def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { 155 let summary = "tensor reshape operation"; 156 let description = [{ 157 Reshape operation is transforming its input tensor into a new tensor with 158 the same number of elements but different shapes. For example: 159 160 ```mlir 161 %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> 162 ``` 163 }]; 164 165 let arguments = (ins F64Tensor:$input); 166 167 // Enabled registering canonicalization patterns with this operation. 168 let hasCanonicalizer = 1; 169 170 // We expect that the reshape operation returns a statically shaped tensor. 171 let results = (outs StaticShapeTensorOf<[F64]>); 172} 173 174def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> { 175 let summary = "return operation"; 176 let description = [{ 177 The "return" operation represents a return operation within a function. 178 The operation takes an optional tensor operand and produces no results. 179 The operand type must match the signature of the function that contains 180 the operation. For example: 181 182 ```mlir 183 func @foo() -> tensor<2xf64> { 184 ... 185 toy.return %0 : tensor<2xf64> 186 } 187 ``` 188 }]; 189 190 // The return operation takes an optional input operand to return. This 191 // value must match the return type of the enclosing function. 192 let arguments = (ins Variadic<F64Tensor>:$input); 193 194 // Allow building a ReturnOp with no return operand. 195 let builders = [OpBuilder< 196 "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] 197 >]; 198 199 // Provide extra utility definitions on the c++ operation class definition. 200 let extraClassDeclaration = [{ 201 bool hasOperand() { return getNumOperands() != 0; } 202 }]; 203 204 // Invoke a static verify method to verify this return operation. 205 let verifier = [{ return ::verify(*this); }]; 206} 207 208def TransposeOp : Toy_Op<"transpose", [NoSideEffect]> { 209 let summary = "transpose operation"; 210 211 let arguments = (ins F64Tensor:$input); 212 let results = (outs F64Tensor); 213 214 // Enabled registering canonicalization patterns with this operation. 215 let hasCanonicalizer = 1; 216 217 // Allow building a TransposeOp with from the input operand. 218 let builders = [ 219 OpBuilder<"Builder *b, OperationState &state, Value input"> 220 ]; 221 222 // Invoke a static verify method to verify this transpose operation. 223 let verifier = [{ return ::verify(*this); }]; 224} 225 226#endif // TOY_OPS 227