1//===- Ops.td - Toy dialect operation definitions ----------*- tablegen -*-===// 2// 3// Part of the LLVM 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/Interfaces/SideEffectInterfaces.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 = "::mlir::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 dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> 51 : tensor<2x3xf64> 52 ``` 53 }]; 54 55 // The constant operation takes an attribute as the only input. 56 let arguments = (ins F64ElementsAttr:$value); 57 58 // The constant operation returns a single value of TensorType. 59 let results = (outs F64Tensor); 60 61 // Specify a parser and printer method. 62 let parser = [{ return ::parseConstantOp(parser, result); }]; 63 let printer = [{ return ::print(p, *this); }]; 64 65 // Add custom build methods for the constant operation. These method populates 66 // the `state` that MLIR uses to create operations, i.e. these are used when 67 // using `builder.create<ConstantOp>(...)`. 68 let builders = [ 69 // Build a constant with a given constant tensor value. 70 OpBuilder<(ins "DenseElementsAttr":$value), [{ 71 build($_builder, $_state, value.getType(), value); 72 }]>, 73 74 // Build a constant with a given constant floating-point value. 75 OpBuilder<(ins "double":$value)> 76 ]; 77 78 // Invoke a static verify method to verify this constant operation. 79 let verifier = [{ return ::verify(*this); }]; 80} 81 82def AddOp : Toy_Op<"add", [NoSideEffect]> { 83 let summary = "element-wise addition operation"; 84 let description = [{ 85 The "add" operation performs element-wise addition between two tensors. 86 The shapes of the tensor operands are expected to match. 87 }]; 88 89 let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); 90 let results = (outs F64Tensor); 91 92 // Specify a parser and printer method. 93 let parser = [{ return ::parseBinaryOp(parser, result); }]; 94 let printer = [{ return ::printBinaryOp(p, *this); }]; 95 96 // Allow building an AddOp with from the two input operands. 97 let builders = [ 98 OpBuilder<(ins "Value":$lhs, "Value":$rhs)> 99 ]; 100} 101 102def GenericCallOp : Toy_Op<"generic_call"> { 103 let summary = "generic call operation"; 104 let description = [{ 105 Generic calls represent calls to a user defined function that needs to 106 be specialized for the shape of its arguments. The callee name is attached 107 as a symbol reference via an attribute. The arguments list must match the 108 arguments expected by the callee. For example: 109 110 ```mlir 111 %4 = toy.generic_call @my_func(%1, %3) 112 : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> 113 ``` 114 115 This is only valid if a function named "my_func" exists and takes two 116 arguments. 117 }]; 118 119 // The generic call operation takes a symbol reference attribute as the 120 // callee, and inputs for the call. 121 let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<F64Tensor>:$inputs); 122 123 // The generic call operation returns a single value of TensorType. 124 let results = (outs F64Tensor); 125 126 // Specialize assembly printing and parsing using a declarative format. 127 let assemblyFormat = [{ 128 $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) 129 }]; 130 131 // Add custom build methods for the generic call operation. 132 let builders = [ 133 OpBuilder<(ins "StringRef":$callee, "ArrayRef<Value>":$arguments)> 134 ]; 135} 136 137def MulOp : Toy_Op<"mul", [NoSideEffect]> { 138 let summary = "element-wise multiplication operation"; 139 let description = [{ 140 The "mul" operation performs element-wise multiplication between two 141 tensors. The shapes of the tensor operands are expected to match. 142 }]; 143 144 let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); 145 let results = (outs F64Tensor); 146 147 // Specify a parser and printer method. 148 let parser = [{ return ::parseBinaryOp(parser, result); }]; 149 let printer = [{ return ::printBinaryOp(p, *this); }]; 150 151 // Allow building a MulOp with from the two input operands. 152 let builders = [ 153 OpBuilder<(ins "Value":$lhs, "Value":$rhs)> 154 ]; 155} 156 157def PrintOp : Toy_Op<"print"> { 158 let summary = "print operation"; 159 let description = [{ 160 The "print" builtin operation prints a given input tensor, and produces 161 no results. 162 }]; 163 164 // The print operation takes an input tensor to print. 165 let arguments = (ins F64Tensor:$input); 166 167 let assemblyFormat = "$input attr-dict `:` type($input)"; 168} 169 170def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { 171 let summary = "tensor reshape operation"; 172 let description = [{ 173 Reshape operation is transforming its input tensor into a new tensor with 174 the same number of elements but different shapes. For example: 175 176 ```mlir 177 %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> 178 ``` 179 }]; 180 181 let arguments = (ins F64Tensor:$input); 182 183 // We expect that the reshape operation returns a statically shaped tensor. 184 let results = (outs StaticShapeTensorOf<[F64]>); 185 186 let assemblyFormat = [{ 187 `(` $input `:` type($input) `)` attr-dict `to` type(results) 188 }]; 189 190 // Enable registering canonicalization patterns with this operation. 191 let hasCanonicalizer = 1; 192} 193 194def ReturnOp : Toy_Op<"return", [NoSideEffect, HasParent<"FuncOp">, 195 Terminator]> { 196 let summary = "return operation"; 197 let description = [{ 198 The "return" operation represents a return operation within a function. 199 The operation takes an optional tensor operand and produces no results. 200 The operand type must match the signature of the function that contains 201 the operation. For example: 202 203 ```mlir 204 func @foo() -> tensor<2xf64> { 205 ... 206 toy.return %0 : tensor<2xf64> 207 } 208 ``` 209 }]; 210 211 // The return operation takes an optional input operand to return. This 212 // value must match the return type of the enclosing function. 213 let arguments = (ins Variadic<F64Tensor>:$input); 214 215 // The return operation only emits the input in the format if it is present. 216 let assemblyFormat = "($input^ `:` type($input))? attr-dict "; 217 218 // Allow building a ReturnOp with no return operand. 219 let builders = [ 220 OpBuilder<(ins), [{ build($_builder, $_state, llvm::None); }]> 221 ]; 222 223 // Provide extra utility definitions on the c++ operation class definition. 224 let extraClassDeclaration = [{ 225 bool hasOperand() { return getNumOperands() != 0; } 226 }]; 227 228 // Invoke a static verify method to verify this return operation. 229 let verifier = [{ return ::verify(*this); }]; 230} 231 232def TransposeOp : Toy_Op<"transpose", [NoSideEffect]> { 233 let summary = "transpose operation"; 234 235 let arguments = (ins F64Tensor:$input); 236 let results = (outs F64Tensor); 237 238 let assemblyFormat = [{ 239 `(` $input `:` type($input) `)` attr-dict `to` type(results) 240 }]; 241 242 // Enable registering canonicalization patterns with this operation. 243 let hasCanonicalizer = 1; 244 245 // Allow building a TransposeOp with from the input operand. 246 let builders = [ 247 OpBuilder<(ins "Value":$input)> 248 ]; 249 250 // Invoke a static verify method to verify this transpose operation. 251 let verifier = [{ return ::verify(*this); }]; 252} 253 254#endif // TOY_OPS 255