xref: /llvm-project/mlir/include/mlir/Dialect/Func/IR/FuncOps.td (revision 35e89897a4086f5adbab10b4b90aa63ef5b35514)
1//===- FuncOps.td - Func 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#ifndef MLIR_DIALECT_FUNC_IR_FUNCOPS_TD
10#define MLIR_DIALECT_FUNC_IR_FUNCOPS_TD
11
12include "mlir/IR/EnumAttr.td"
13include "mlir/IR/OpAsmInterface.td"
14include "mlir/IR/SymbolInterfaces.td"
15include "mlir/Interfaces/CallInterfaces.td"
16include "mlir/Interfaces/ControlFlowInterfaces.td"
17include "mlir/Interfaces/FunctionInterfaces.td"
18include "mlir/Interfaces/InferTypeOpInterface.td"
19include "mlir/Interfaces/SideEffectInterfaces.td"
20
21def Func_Dialect : Dialect {
22  let name = "func";
23  let cppNamespace = "::mlir::func";
24  let hasConstantMaterializer = 1;
25}
26
27// Base class for Func dialect ops.
28class Func_Op<string mnemonic, list<Trait> traits = []> :
29    Op<Func_Dialect, mnemonic, traits>;
30
31//===----------------------------------------------------------------------===//
32// CallOp
33//===----------------------------------------------------------------------===//
34
35def CallOp : Func_Op<"call",
36    [CallOpInterface, MemRefsNormalizable,
37     DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
38  let summary = "call operation";
39  let description = [{
40    The `func.call` operation represents a direct call to a function that is
41    within the same symbol scope as the call. The operands and result types of
42    the call must match the specified function type. The callee is encoded as a
43    symbol reference attribute named "callee".
44
45    Example:
46
47    ```mlir
48    %2 = func.call @my_add(%0, %1) : (f32, f32) -> f32
49    ```
50  }];
51
52  let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$operands,
53                       UnitAttr:$no_inline);
54  let results = (outs Variadic<AnyType>);
55
56  let builders = [
57    OpBuilder<(ins "FuncOp":$callee, CArg<"ValueRange", "{}">:$operands), [{
58      $_state.addOperands(operands);
59      $_state.addAttribute("callee", SymbolRefAttr::get(callee));
60      $_state.addTypes(callee.getFunctionType().getResults());
61    }]>,
62    OpBuilder<(ins "SymbolRefAttr":$callee, "TypeRange":$results,
63      CArg<"ValueRange", "{}">:$operands), [{
64      $_state.addOperands(operands);
65      $_state.addAttribute("callee", callee);
66      $_state.addTypes(results);
67    }]>,
68    OpBuilder<(ins "StringAttr":$callee, "TypeRange":$results,
69      CArg<"ValueRange", "{}">:$operands), [{
70      build($_builder, $_state, SymbolRefAttr::get(callee), results, operands);
71    }]>,
72    OpBuilder<(ins "StringRef":$callee, "TypeRange":$results,
73      CArg<"ValueRange", "{}">:$operands), [{
74      build($_builder, $_state, StringAttr::get($_builder.getContext(), callee),
75            results, operands);
76    }]>];
77
78  let extraClassDeclaration = [{
79    FunctionType getCalleeType();
80
81    /// Get the argument operands to the called function.
82    operand_range getArgOperands() {
83      return {arg_operand_begin(), arg_operand_end()};
84    }
85
86    MutableOperandRange getArgOperandsMutable() {
87      return getOperandsMutable();
88    }
89
90    operand_iterator arg_operand_begin() { return operand_begin(); }
91    operand_iterator arg_operand_end() { return operand_end(); }
92
93    /// Return the callee of this operation.
94    CallInterfaceCallable getCallableForCallee() {
95      return (*this)->getAttrOfType<SymbolRefAttr>("callee");
96    }
97
98    /// Set the callee for this operation.
99    void setCalleeFromCallable(CallInterfaceCallable callee) {
100      (*this)->setAttr("callee", cast<SymbolRefAttr>(callee));
101    }
102  }];
103
104  let assemblyFormat = [{
105    $callee `(` $operands `)` attr-dict `:` functional-type($operands, results)
106  }];
107}
108
109//===----------------------------------------------------------------------===//
110// CallIndirectOp
111//===----------------------------------------------------------------------===//
112
113def CallIndirectOp : Func_Op<"call_indirect", [
114      CallOpInterface,
115      TypesMatchWith<"callee input types match argument types",
116                     "callee", "callee_operands",
117                     "::llvm::cast<FunctionType>($_self).getInputs()">,
118      TypesMatchWith<"callee result types match result types",
119                     "callee", "results",
120                     "::llvm::cast<FunctionType>($_self).getResults()">
121    ]> {
122  let summary = "indirect call operation";
123  let description = [{
124    The `func.call_indirect` operation represents an indirect call to a value
125    of function type. The operands and result types of the call must match the
126    specified function type.
127
128    Function values can be created with the
129    [`func.constant` operation](#funcconstant-constantop).
130
131    Example:
132
133    ```mlir
134    %func = func.constant @my_func : (tensor<16xf32>, tensor<16xf32>) -> tensor<16xf32>
135    %result = func.call_indirect %func(%0, %1) : (tensor<16xf32>, tensor<16xf32>) -> tensor<16xf32>
136    ```
137  }];
138
139  let arguments = (ins FunctionType:$callee,
140                       Variadic<AnyType>:$callee_operands);
141  let results = (outs Variadic<AnyType>:$results);
142
143  let builders = [
144    OpBuilder<(ins "Value":$callee, CArg<"ValueRange", "{}">:$operands), [{
145      $_state.operands.push_back(callee);
146      $_state.addOperands(operands);
147      $_state.addTypes(::llvm::cast<FunctionType>(callee.getType()).getResults());
148    }]>];
149
150  let extraClassDeclaration = [{
151    // TODO: Remove once migrated callers.
152    ValueRange operands() { return getCalleeOperands(); }
153
154    /// Get the argument operands to the called function.
155    operand_range getArgOperands() {
156      return {arg_operand_begin(), arg_operand_end()};
157    }
158
159    MutableOperandRange getArgOperandsMutable() {
160      return getCalleeOperandsMutable();
161    }
162
163    operand_iterator arg_operand_begin() { return ++operand_begin(); }
164    operand_iterator arg_operand_end() { return operand_end(); }
165
166    /// Return the callee of this operation.
167    CallInterfaceCallable getCallableForCallee() { return getCallee(); }
168
169    /// Set the callee for this operation.
170    void setCalleeFromCallable(CallInterfaceCallable callee) {
171      setOperand(0, cast<Value>(callee));
172    }
173  }];
174
175  let hasCanonicalizeMethod = 1;
176  let assemblyFormat = [{
177    $callee `(` $callee_operands `)` attr-dict `:` type($callee)
178  }];
179}
180
181//===----------------------------------------------------------------------===//
182// ConstantOp
183//===----------------------------------------------------------------------===//
184
185def ConstantOp : Func_Op<"constant",
186    [ConstantLike, Pure,
187     DeclareOpInterfaceMethods<SymbolUserOpInterface>,
188     DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>]> {
189  let summary = "constant";
190  let description = [{
191    The `func.constant` operation produces an SSA value from a symbol reference
192    to a `func.func` operation
193
194    Example:
195
196    ```mlir
197    // Reference to function @myfn.
198    %2 = func.constant @myfn : (tensor<16xf32>, f32) -> tensor<16xf32>
199
200    // Equivalent generic forms
201    %2 = "func.constant"() { value = @myfn } : () -> ((tensor<16xf32>, f32) -> tensor<16xf32>)
202    ```
203
204    MLIR does not allow direct references to functions in SSA operands because
205    the compiler is multithreaded, and disallowing SSA values to directly
206    reference a function simplifies this
207    ([rationale](../Rationale/Rationale.md#multithreading-the-compiler)).
208  }];
209
210  let arguments = (ins FlatSymbolRefAttr:$value);
211  let results = (outs AnyType);
212  let assemblyFormat = "attr-dict $value `:` type(results)";
213
214  let extraClassDeclaration = [{
215    /// Returns true if a constant operation can be built with the given value
216    /// and result type.
217    static bool isBuildableWith(Attribute value, Type type);
218  }];
219
220  let hasFolder = 1;
221}
222
223//===----------------------------------------------------------------------===//
224// FuncOp
225//===----------------------------------------------------------------------===//
226
227def FuncOp : Func_Op<"func", [
228  AffineScope, AutomaticAllocationScope,
229  FunctionOpInterface, IsolatedFromAbove, OpAsmOpInterface
230]> {
231  let summary = "An operation with a name containing a single `SSACFG` region";
232  let description = [{
233    Operations within the function cannot implicitly capture values defined
234    outside of the function, i.e. Functions are `IsolatedFromAbove`. All
235    external references must use function arguments or attributes that establish
236    a symbolic connection (e.g. symbols referenced by name via a string
237    attribute like SymbolRefAttr). An external function declaration (used when
238    referring to a function declared in some other module) has no body. While
239    the MLIR textual form provides a nice inline syntax for function arguments,
240    they are internally represented as “block arguments” to the first block in
241    the region.
242
243    Only dialect attribute names may be specified in the attribute dictionaries
244    for function arguments, results, or the function itself.
245
246    Example:
247
248    ```mlir
249    // External function definitions.
250    func.func private @abort()
251    func.func private @scribble(i32, i64, memref<? x 128 x f32, #layout_map0>) -> f64
252
253    // A function that returns its argument twice:
254    func.func @count(%x: i64) -> (i64, i64)
255      attributes {fruit = "banana"} {
256      return %x, %x: i64, i64
257    }
258
259    // A function with an argument attribute
260    func.func private @example_fn_arg(%x: i32 {swift.self = unit})
261
262    // A function with a result attribute
263    func.func private @example_fn_result() -> (f64 {dialectName.attrName = 0 : i64})
264
265    // A function with an attribute
266    func.func private @example_fn_attr() attributes {dialectName.attrName = false}
267    ```
268  }];
269
270  let arguments = (ins SymbolNameAttr:$sym_name,
271                       TypeAttrOf<FunctionType>:$function_type,
272                       OptionalAttr<StrAttr>:$sym_visibility,
273                       OptionalAttr<DictArrayAttr>:$arg_attrs,
274                       OptionalAttr<DictArrayAttr>:$res_attrs,
275                       UnitAttr:$no_inline);
276  let regions = (region AnyRegion:$body);
277
278  let builders = [OpBuilder<(ins
279    "StringRef":$name, "FunctionType":$type,
280    CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
281    CArg<"ArrayRef<DictionaryAttr>", "{}">:$argAttrs)
282  >];
283  let extraClassDeclaration = [{
284    static FuncOp create(Location location, StringRef name, FunctionType type,
285                         ArrayRef<NamedAttribute> attrs = {});
286    static FuncOp create(Location location, StringRef name, FunctionType type,
287                         Operation::dialect_attr_range attrs);
288    static FuncOp create(Location location, StringRef name, FunctionType type,
289                         ArrayRef<NamedAttribute> attrs,
290                         ArrayRef<DictionaryAttr> argAttrs);
291
292    /// Create a deep copy of this function and all of its blocks, remapping any
293    /// operands that use values outside of the function using the map that is
294    /// provided (leaving them alone if no entry is present). If the mapper
295    /// contains entries for function arguments, these arguments are not
296    /// included in the new function. Replaces references to cloned sub-values
297    /// with the corresponding value that is copied, and adds those mappings to
298    /// the mapper.
299    FuncOp clone(IRMapping &mapper);
300    FuncOp clone();
301
302    /// Clone the internal blocks and attributes from this function into dest.
303    /// Any cloned blocks are appended to the back of dest. This function
304    /// asserts that the attributes of the current function and dest are
305    /// compatible.
306    void cloneInto(FuncOp dest, IRMapping &mapper);
307
308    //===------------------------------------------------------------------===//
309    // FunctionOpInterface Methods
310    //===------------------------------------------------------------------===//
311
312    /// Returns the region on the current operation that is callable. This may
313    /// return null in the case of an external callable object, e.g. an external
314    /// function.
315    ::mlir::Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
316
317    /// Returns the argument types of this function.
318    ArrayRef<Type> getArgumentTypes() { return getFunctionType().getInputs(); }
319
320    /// Returns the result types of this function.
321    ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }
322
323    //===------------------------------------------------------------------===//
324    // OpAsmOpInterface Methods
325    //===------------------------------------------------------------------===//
326
327    /// Allow the dialect prefix to be omitted.
328    static StringRef getDefaultDialect() { return "func"; }
329
330    //===------------------------------------------------------------------===//
331    // SymbolOpInterface Methods
332    //===------------------------------------------------------------------===//
333
334    bool isDeclaration() { return isExternal(); }
335  }];
336  let hasCustomAssemblyFormat = 1;
337}
338
339//===----------------------------------------------------------------------===//
340// ReturnOp
341//===----------------------------------------------------------------------===//
342
343def ReturnOp : Func_Op<"return", [Pure, HasParent<"FuncOp">,
344                                MemRefsNormalizable, ReturnLike, Terminator]> {
345  let summary = "Function return operation";
346  let description = [{
347    The `func.return` operation represents a return operation within a function.
348    The operation takes variable number of operands and produces no results.
349    The operand number and types must match the signature of the function
350    that contains the operation.
351
352    Example:
353
354    ```mlir
355    func.func @foo() -> (i32, f8) {
356      ...
357      return %0, %1 : i32, f8
358    }
359    ```
360  }];
361
362  let arguments = (ins Variadic<AnyType>:$operands);
363
364  let builders = [OpBuilder<(ins), [{
365    build($_builder, $_state, std::nullopt);
366  }]>];
367
368  let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
369  let hasVerifier = 1;
370}
371
372#endif // MLIR_DIALECT_FUNC_IR_FUNCOPS_TD
373