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