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