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