xref: /llvm-project/mlir/include/mlir/Interfaces/FunctionInterfaces.td (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
1//===- FunctionInterfaces.td - Function interfaces --------*- 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// This file contains definitions for interfaces that support the definition of
10// "function-like" operations.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_INTERFACES_FUNCTIONINTERFACES_TD_
15#define MLIR_INTERFACES_FUNCTIONINTERFACES_TD_
16
17include "mlir/IR/SymbolInterfaces.td"
18include "mlir/Interfaces/CallInterfaces.td"
19
20//===----------------------------------------------------------------------===//
21// FunctionOpInterface
22//===----------------------------------------------------------------------===//
23
24def FunctionOpInterface : OpInterface<"FunctionOpInterface", [
25    Symbol, CallableOpInterface
26  ]> {
27  let cppNamespace = "::mlir";
28  let description = [{
29    This interfaces provides support for interacting with operations that
30    behave like functions. In particular, these operations:
31
32      - must be symbols, i.e. have the `Symbol` trait.
33      - must have a single region, that may be comprised with multiple blocks,
34        that corresponds to the function body.
35        * when this region is empty, the operation corresponds to an external
36          function.
37        * leading arguments of the first block of the region are treated as
38          function arguments.
39
40    The function, aside from implementing the various interface methods,
41    should have the following ODS arguments:
42
43      - `function_type` (required)
44        * A TypeAttr that holds the signature type of the function.
45
46      - `arg_attrs` (optional)
47        * An ArrayAttr of DictionaryAttr that contains attribute dictionaries
48          for each of the function arguments.
49
50      - `res_attrs` (optional)
51        * An ArrayAttr of DictionaryAttr that contains attribute dictionaries
52          for each of the function results.
53  }];
54  let methods = [
55    InterfaceMethod<[{
56      Returns the type of the function.
57    }],
58    "::mlir::Type", "getFunctionType">,
59    InterfaceMethod<[{
60      Set the type of the function. This method should perform an unsafe
61      modification to the function type; it should not update argument or
62      result attributes.
63    }],
64    "void", "setFunctionTypeAttr", (ins "::mlir::TypeAttr":$type)>,
65
66    InterfaceMethod<[{
67      Returns a clone of the function type with the given argument and
68      result types.
69
70      Note: The default implementation assumes the function type has
71            an appropriate clone method:
72              `Type clone(ArrayRef<Type> inputs, ArrayRef<Type> results)`
73    }],
74    "::mlir::Type", "cloneTypeWith", (ins
75      "::mlir::TypeRange":$inputs, "::mlir::TypeRange":$results
76    ), /*methodBody=*/[{}], /*defaultImplementation=*/[{
77      return $_op.getFunctionType().clone(inputs, results);
78    }]>,
79
80    InterfaceMethod<[{
81      Verify the contents of the body of this function.
82
83      Note: The default implementation merely checks that if the entry block
84      exists, it has the same number and type of arguments as the function type.
85    }],
86    "::llvm::LogicalResult", "verifyBody", (ins),
87    /*methodBody=*/[{}], /*defaultImplementation=*/[{
88      if ($_op.isExternal())
89        return success();
90      ArrayRef<Type> fnInputTypes = $_op.getArgumentTypes();
91      // NOTE: This should just be $_op.front() but access generically
92      // because the interface methods defined here may be shadowed in
93      // arbitrary ways. https://github.com/llvm/llvm-project/issues/54807
94      Block &entryBlock = $_op->getRegion(0).front();
95
96      unsigned numArguments = fnInputTypes.size();
97      if (entryBlock.getNumArguments() != numArguments)
98        return $_op.emitOpError("entry block must have ")
99              << numArguments << " arguments to match function signature";
100
101      for (unsigned i = 0, e = fnInputTypes.size(); i != e; ++i) {
102        Type argType = entryBlock.getArgument(i).getType();
103        if (fnInputTypes[i] != argType) {
104          return $_op.emitOpError("type of entry block argument #")
105                << i << '(' << argType
106                << ") must match the type of the corresponding argument in "
107                << "function signature(" << fnInputTypes[i] << ')';
108        }
109      }
110
111      return success();
112    }]>,
113    InterfaceMethod<[{
114      Verify the type attribute of the function for derived op-specific
115      invariants.
116    }],
117    "::llvm::LogicalResult", "verifyType", (ins),
118    /*methodBody=*/[{}], /*defaultImplementation=*/[{
119      return success();
120    }]>,
121  ];
122
123  let extraTraitClassDeclaration = [{
124    //===------------------------------------------------------------------===//
125    // Builders
126    //===------------------------------------------------------------------===//
127
128    /// Build the function with the given name, attributes, and type. This
129    /// builder also inserts an entry block into the function body with the
130    /// given argument types.
131    static void buildWithEntryBlock(
132        OpBuilder &builder, OperationState &state, StringRef name, Type type,
133        ArrayRef<NamedAttribute> attrs, TypeRange inputTypes) {
134      OpBuilder::InsertionGuard g(builder);
135      state.addAttribute(SymbolTable::getSymbolAttrName(),
136                        builder.getStringAttr(name));
137      state.addAttribute(ConcreteOp::getFunctionTypeAttrName(state.name),
138                        TypeAttr::get(type));
139      state.attributes.append(attrs.begin(), attrs.end());
140
141      // Add the function body.
142      Region *bodyRegion = state.addRegion();
143      Block *body = builder.createBlock(bodyRegion);
144      for (Type input : inputTypes)
145        body->addArgument(input, state.location);
146    }
147  }];
148  let extraSharedClassDeclaration = [{
149    /// Block list iterator types.
150    using BlockListType = ::mlir::Region::BlockListType;
151    using iterator = BlockListType::iterator;
152    using reverse_iterator = BlockListType::reverse_iterator;
153
154    /// Block argument iterator types.
155    using BlockArgListType = ::mlir::Region::BlockArgListType;
156    using args_iterator = BlockArgListType::iterator;
157
158    //===------------------------------------------------------------------===//
159    // Body Handling
160    //===------------------------------------------------------------------===//
161
162    /// Returns true if this function is external, i.e. it has no body.
163    bool isExternal() { return empty(); }
164
165    /// Return the region containing the body of this function.
166    ::mlir::Region &getFunctionBody() { return $_op->getRegion(0); }
167
168    /// Delete all blocks from this function.
169    void eraseBody() {
170      getFunctionBody().dropAllReferences();
171      getFunctionBody().getBlocks().clear();
172    }
173
174    /// Return the list of blocks within the function body.
175    BlockListType &getBlocks() { return getFunctionBody().getBlocks(); }
176
177    iterator begin() { return getFunctionBody().begin(); }
178    iterator end() { return getFunctionBody().end(); }
179    reverse_iterator rbegin() { return getFunctionBody().rbegin(); }
180    reverse_iterator rend() { return getFunctionBody().rend(); }
181
182    /// Returns true if this function has no blocks within the body.
183    bool empty() { return getFunctionBody().empty(); }
184
185    /// Push a new block to the back of the body region.
186    void push_back(::mlir::Block *block) { getFunctionBody().push_back(block); }
187
188    /// Push a new block to the front of the body region.
189    void push_front(::mlir::Block *block) { getFunctionBody().push_front(block); }
190
191    /// Return the last block in the body region.
192    ::mlir::Block &back() { return getFunctionBody().back(); }
193
194    /// Return the first block in the body region.
195    ::mlir::Block &front() { return getFunctionBody().front(); }
196
197    /// Add an entry block to an empty function, and set up the block arguments
198    /// to match the signature of the function. The newly inserted entry block
199    /// is returned.
200    ::mlir::Block *addEntryBlock() {
201      assert(empty() && "function already has an entry block");
202      ::mlir::Block *entry = new ::mlir::Block();
203      push_back(entry);
204
205      // FIXME: Allow for passing in locations for these arguments instead of using
206      // the operations location.
207      ::llvm::ArrayRef<::mlir::Type> inputTypes = $_op.getArgumentTypes();
208      ::llvm::SmallVector<::mlir::Location> locations(inputTypes.size(),
209                                              $_op.getOperation()->getLoc());
210      entry->addArguments(inputTypes, locations);
211      return entry;
212    }
213
214    /// Add a normal block to the end of the function's block list. The function
215    /// should at least already have an entry block.
216    ::mlir::Block *addBlock() {
217      assert(!empty() && "function should at least have an entry block");
218      push_back(new ::mlir::Block());
219      return &back();
220    }
221
222    //===------------------------------------------------------------------===//
223    // Type Attribute Handling
224    //===------------------------------------------------------------------===//
225
226    /// Change the type of this function in place. This is an extremely dangerous
227    /// operation and it is up to the caller to ensure that this is legal for
228    /// this function, and to restore invariants:
229    ///  - the entry block args must be updated to match the function params.
230    ///  - the argument/result attributes may need an update: if the new type
231    ///    has less parameters we drop the extra attributes, if there are more
232    ///    parameters they won't have any attributes.
233    void setType(::mlir::Type newType) {
234      ::mlir::function_interface_impl::setFunctionType($_op, newType);
235    }
236
237    //===------------------------------------------------------------------===//
238    // Argument and Result Handling
239    //===------------------------------------------------------------------===//
240
241    /// Returns the number of function arguments.
242    unsigned getNumArguments() { return $_op.getArgumentTypes().size(); }
243
244    /// Returns the number of function results.
245    unsigned getNumResults() { return $_op.getResultTypes().size(); }
246
247    /// Returns the entry block function argument at the given index.
248    ::mlir::BlockArgument getArgument(unsigned idx) {
249      return getFunctionBody().getArgument(idx);
250    }
251
252    /// Support argument iteration.
253    args_iterator args_begin() { return getFunctionBody().args_begin(); }
254    args_iterator args_end() { return getFunctionBody().args_end(); }
255    BlockArgListType getArguments() { return getFunctionBody().getArguments(); }
256
257    /// Insert a single argument of type `argType` with attributes `argAttrs` and
258    /// location `argLoc` at `argIndex`.
259    void insertArgument(unsigned argIndex, ::mlir::Type argType, ::mlir::DictionaryAttr argAttrs,
260                        ::mlir::Location argLoc) {
261      insertArguments({argIndex}, {argType}, {argAttrs}, {argLoc});
262    }
263
264    /// Inserts arguments with the listed types, attributes, and locations at the
265    /// listed indices. `argIndices` must be sorted. Arguments are inserted in the
266    /// order they are listed, such that arguments with identical index will
267    /// appear in the same order that they were listed here.
268    void insertArguments(::llvm::ArrayRef<unsigned> argIndices, ::mlir::TypeRange argTypes,
269                        ::llvm::ArrayRef<::mlir::DictionaryAttr> argAttrs,
270                        ::llvm::ArrayRef<::mlir::Location> argLocs) {
271      unsigned originalNumArgs = $_op.getNumArguments();
272      ::mlir::Type newType = $_op.getTypeWithArgsAndResults(
273          argIndices, argTypes, /*resultIndices=*/{}, /*resultTypes=*/{});
274      ::mlir::function_interface_impl::insertFunctionArguments(
275          $_op, argIndices, argTypes, argAttrs, argLocs,
276          originalNumArgs, newType);
277    }
278
279    /// Insert a single result of type `resultType` at `resultIndex`.
280    void insertResult(unsigned resultIndex, ::mlir::Type resultType,
281                      ::mlir::DictionaryAttr resultAttrs) {
282      insertResults({resultIndex}, {resultType}, {resultAttrs});
283    }
284
285    /// Inserts results with the listed types at the listed indices.
286    /// `resultIndices` must be sorted. Results are inserted in the order they are
287    /// listed, such that results with identical index will appear in the same
288    /// order that they were listed here.
289    void insertResults(::llvm::ArrayRef<unsigned> resultIndices, ::mlir::TypeRange resultTypes,
290                       ::llvm::ArrayRef<::mlir::DictionaryAttr> resultAttrs) {
291      unsigned originalNumResults = $_op.getNumResults();
292      ::mlir::Type newType = $_op.getTypeWithArgsAndResults(
293        /*argIndices=*/{}, /*argTypes=*/{}, resultIndices, resultTypes);
294      ::mlir::function_interface_impl::insertFunctionResults(
295          $_op, resultIndices, resultTypes, resultAttrs,
296          originalNumResults, newType);
297    }
298
299    /// Erase a single argument at `argIndex`.
300    void eraseArgument(unsigned argIndex) {
301      ::llvm::BitVector argsToErase($_op.getNumArguments());
302      argsToErase.set(argIndex);
303      eraseArguments(argsToErase);
304    }
305
306    /// Erases the arguments listed in `argIndices`.
307    void eraseArguments(const ::llvm::BitVector &argIndices) {
308      ::mlir::Type newType = $_op.getTypeWithoutArgs(argIndices);
309      ::mlir::function_interface_impl::eraseFunctionArguments(
310        $_op, argIndices, newType);
311    }
312
313    /// Erase a single result at `resultIndex`.
314    void eraseResult(unsigned resultIndex) {
315      ::llvm::BitVector resultsToErase($_op.getNumResults());
316      resultsToErase.set(resultIndex);
317      eraseResults(resultsToErase);
318    }
319
320    /// Erases the results listed in `resultIndices`.
321    void eraseResults(const ::llvm::BitVector &resultIndices) {
322      ::mlir::Type newType = $_op.getTypeWithoutResults(resultIndices);
323      ::mlir::function_interface_impl::eraseFunctionResults(
324          $_op, resultIndices, newType);
325    }
326
327    /// Return the type of this function with the specified arguments and
328    /// results inserted. This is used to update the function's signature in
329    /// the `insertArguments` and `insertResults` methods. The arrays must be
330    /// sorted by increasing index.
331    ::mlir::Type getTypeWithArgsAndResults(
332      ::llvm::ArrayRef<unsigned> argIndices, ::mlir::TypeRange argTypes,
333      ::llvm::ArrayRef<unsigned> resultIndices, ::mlir::TypeRange resultTypes) {
334      ::llvm::SmallVector<::mlir::Type> argStorage, resultStorage;
335      ::mlir::TypeRange newArgTypes = insertTypesInto(
336          $_op.getArgumentTypes(), argIndices, argTypes, argStorage);
337      ::mlir::TypeRange newResultTypes = insertTypesInto(
338          $_op.getResultTypes(), resultIndices, resultTypes, resultStorage);
339      return $_op.cloneTypeWith(newArgTypes, newResultTypes);
340    }
341
342    /// Return the type of this function without the specified arguments and
343    /// results. This is used to update the function's signature in the
344    /// `eraseArguments` and `eraseResults` methods.
345    ::mlir::Type getTypeWithoutArgsAndResults(
346      const ::llvm::BitVector &argIndices, const ::llvm::BitVector &resultIndices) {
347      ::llvm::SmallVector<::mlir::Type> argStorage, resultStorage;
348      ::mlir::TypeRange newArgTypes = filterTypesOut(
349          $_op.getArgumentTypes(), argIndices, argStorage);
350      ::mlir::TypeRange newResultTypes = filterTypesOut(
351          $_op.getResultTypes(), resultIndices, resultStorage);
352      return $_op.cloneTypeWith(newArgTypes, newResultTypes);
353    }
354    ::mlir::Type getTypeWithoutArgs(const ::llvm::BitVector &argIndices) {
355      ::llvm::SmallVector<::mlir::Type> argStorage;
356      ::mlir::TypeRange newArgTypes = filterTypesOut(
357          $_op.getArgumentTypes(), argIndices, argStorage);
358      return $_op.cloneTypeWith(newArgTypes, $_op.getResultTypes());
359    }
360    ::mlir::Type getTypeWithoutResults(const ::llvm::BitVector &resultIndices) {
361      ::llvm::SmallVector<::mlir::Type> resultStorage;
362      ::mlir::TypeRange newResultTypes = filterTypesOut(
363          $_op.getResultTypes(), resultIndices, resultStorage);
364      return $_op.cloneTypeWith($_op.getArgumentTypes(), newResultTypes);
365    }
366
367    //===------------------------------------------------------------------===//
368    // Argument Attributes
369    //===------------------------------------------------------------------===//
370
371    /// Return all of the attributes for the argument at 'index'.
372    ::llvm::ArrayRef<::mlir::NamedAttribute> getArgAttrs(unsigned index) {
373      return ::mlir::function_interface_impl::getArgAttrs($_op, index);
374    }
375
376    /// Return an ArrayAttr containing all argument attribute dictionaries of
377    /// this function, or nullptr if no arguments have attributes.
378    ::mlir::ArrayAttr getAllArgAttrs() { return $_op.getArgAttrsAttr(); }
379
380    /// Return all argument attributes of this function.
381    void getAllArgAttrs(::llvm::SmallVectorImpl<::mlir::DictionaryAttr> &result) {
382      if (::mlir::ArrayAttr argAttrs = getAllArgAttrs()) {
383        auto argAttrRange = argAttrs.template getAsRange<::mlir::DictionaryAttr>();
384        result.append(argAttrRange.begin(), argAttrRange.end());
385      } else {
386        result.append($_op.getNumArguments(),
387                      ::mlir::DictionaryAttr::get(this->getOperation()->getContext()));
388      }
389    }
390
391    /// Return the specified attribute, if present, for the argument at 'index',
392    /// null otherwise.
393    ::mlir::Attribute getArgAttr(unsigned index, ::mlir::StringAttr name) {
394      auto argDict = getArgAttrDict(index);
395      return argDict ? argDict.get(name) : nullptr;
396    }
397    ::mlir::Attribute getArgAttr(unsigned index, ::llvm::StringRef name) {
398      auto argDict = getArgAttrDict(index);
399      return argDict ? argDict.get(name) : nullptr;
400    }
401
402    template <typename AttrClass>
403    AttrClass getArgAttrOfType(unsigned index, ::mlir::StringAttr name) {
404      return ::llvm::dyn_cast_or_null<AttrClass>(getArgAttr(index, name));
405    }
406    template <typename AttrClass>
407    AttrClass getArgAttrOfType(unsigned index, ::llvm::StringRef name) {
408      return ::llvm::dyn_cast_or_null<AttrClass>(getArgAttr(index, name));
409    }
410
411    /// Set the attributes held by the argument at 'index'.
412    void setArgAttrs(unsigned index, ::llvm::ArrayRef<::mlir::NamedAttribute> attributes) {
413      ::mlir::function_interface_impl::setArgAttrs($_op, index, attributes);
414    }
415
416    /// Set the attributes held by the argument at 'index'. `attributes` may be
417    /// null, in which case any existing argument attributes are removed.
418    void setArgAttrs(unsigned index, ::mlir::DictionaryAttr attributes) {
419      ::mlir::function_interface_impl::setArgAttrs($_op, index, attributes);
420    }
421    void setAllArgAttrs(::llvm::ArrayRef<::mlir::DictionaryAttr> attributes) {
422      assert(attributes.size() == $_op.getNumArguments());
423      ::mlir::function_interface_impl::setAllArgAttrDicts($_op, attributes);
424    }
425    void setAllArgAttrs(::llvm::ArrayRef<::mlir::Attribute> attributes) {
426      assert(attributes.size() == $_op.getNumArguments());
427      ::mlir::function_interface_impl::setAllArgAttrDicts($_op, attributes);
428    }
429    void setAllArgAttrs(::mlir::ArrayAttr attributes) {
430      assert(attributes.size() == $_op.getNumArguments());
431      $_op.setArgAttrsAttr(attributes);
432    }
433
434    /// If the an attribute exists with the specified name, change it to the new
435    /// value. Otherwise, add a new attribute with the specified name/value.
436    void setArgAttr(unsigned index, ::mlir::StringAttr name, ::mlir::Attribute value) {
437      ::mlir::function_interface_impl::setArgAttr($_op, index, name, value);
438    }
439    void setArgAttr(unsigned index, ::llvm::StringRef name, ::mlir::Attribute value) {
440      setArgAttr(index,
441                 ::mlir::StringAttr::get(this->getOperation()->getContext(), name),
442                 value);
443    }
444
445    /// Remove the attribute 'name' from the argument at 'index'. Return the
446    /// attribute that was erased, or nullptr if there was no attribute with
447    /// such name.
448    ::mlir::Attribute removeArgAttr(unsigned index, ::mlir::StringAttr name) {
449      return ::mlir::function_interface_impl::removeArgAttr($_op, index, name);
450    }
451    ::mlir::Attribute removeArgAttr(unsigned index, ::llvm::StringRef name) {
452      return removeArgAttr(
453          index, ::mlir::StringAttr::get(this->getOperation()->getContext(), name));
454    }
455
456    //===------------------------------------------------------------------===//
457    // Result Attributes
458    //===------------------------------------------------------------------===//
459
460    /// Return all of the attributes for the result at 'index'.
461    ::llvm::ArrayRef<::mlir::NamedAttribute> getResultAttrs(unsigned index) {
462      return ::mlir::function_interface_impl::getResultAttrs($_op, index);
463    }
464
465    /// Return an ArrayAttr containing all result attribute dictionaries of this
466    /// function, or nullptr if no result have attributes.
467    ::mlir::ArrayAttr getAllResultAttrs() { return $_op.getResAttrsAttr(); }
468
469    /// Return all result attributes of this function.
470    void getAllResultAttrs(::llvm::SmallVectorImpl<::mlir::DictionaryAttr> &result) {
471      if (::mlir::ArrayAttr argAttrs = getAllResultAttrs()) {
472        auto argAttrRange = argAttrs.template getAsRange<::mlir::DictionaryAttr>();
473        result.append(argAttrRange.begin(), argAttrRange.end());
474      } else {
475        result.append($_op.getNumResults(),
476                      ::mlir::DictionaryAttr::get(this->getOperation()->getContext()));
477      }
478    }
479
480    /// Return the specified attribute, if present, for the result at 'index',
481    /// null otherwise.
482    ::mlir::Attribute getResultAttr(unsigned index, ::mlir::StringAttr name) {
483      auto argDict = getResultAttrDict(index);
484      return argDict ? argDict.get(name) : nullptr;
485    }
486    ::mlir::Attribute getResultAttr(unsigned index, ::llvm::StringRef name) {
487      auto argDict = getResultAttrDict(index);
488      return argDict ? argDict.get(name) : nullptr;
489    }
490
491    template <typename AttrClass>
492    AttrClass getResultAttrOfType(unsigned index, ::mlir::StringAttr name) {
493      return ::llvm::dyn_cast_or_null<AttrClass>(getResultAttr(index, name));
494    }
495    template <typename AttrClass>
496    AttrClass getResultAttrOfType(unsigned index, ::llvm::StringRef name) {
497      return ::llvm::dyn_cast_or_null<AttrClass>(getResultAttr(index, name));
498    }
499
500    /// Set the attributes held by the result at 'index'.
501    void setResultAttrs(unsigned index, ::llvm::ArrayRef<::mlir::NamedAttribute> attributes) {
502      ::mlir::function_interface_impl::setResultAttrs($_op, index, attributes);
503    }
504
505    /// Set the attributes held by the result at 'index'. `attributes` may be
506    /// null, in which case any existing argument attributes are removed.
507    void setResultAttrs(unsigned index, ::mlir::DictionaryAttr attributes) {
508      ::mlir::function_interface_impl::setResultAttrs($_op, index, attributes);
509    }
510    void setAllResultAttrs(::llvm::ArrayRef<::mlir::DictionaryAttr> attributes) {
511      assert(attributes.size() == $_op.getNumResults());
512      ::mlir::function_interface_impl::setAllResultAttrDicts(
513        $_op, attributes);
514    }
515    void setAllResultAttrs(::llvm::ArrayRef<::mlir::Attribute> attributes) {
516      assert(attributes.size() == $_op.getNumResults());
517      ::mlir::function_interface_impl::setAllResultAttrDicts(
518        $_op, attributes);
519    }
520    void setAllResultAttrs(::mlir::ArrayAttr attributes) {
521      assert(attributes.size() == $_op.getNumResults());
522      $_op.setResAttrsAttr(attributes);
523    }
524
525    /// If the an attribute exists with the specified name, change it to the new
526    /// value. Otherwise, add a new attribute with the specified name/value.
527    void setResultAttr(unsigned index, ::mlir::StringAttr name, ::mlir::Attribute value) {
528      ::mlir::function_interface_impl::setResultAttr($_op, index, name, value);
529    }
530    void setResultAttr(unsigned index, ::llvm::StringRef name, ::mlir::Attribute value) {
531      setResultAttr(index,
532                    ::mlir::StringAttr::get(this->getOperation()->getContext(), name),
533                    value);
534    }
535
536    /// Remove the attribute 'name' from the result at 'index'. Return the
537    /// attribute that was erased, or nullptr if there was no attribute with
538    /// such name.
539    ::mlir::Attribute removeResultAttr(unsigned index, ::mlir::StringAttr name) {
540      return ::mlir::function_interface_impl::removeResultAttr($_op, index, name);
541    }
542
543    /// Returns the dictionary attribute corresponding to the argument at
544    /// 'index'. If there are no argument attributes at 'index', a null
545    /// attribute is returned.
546    ::mlir::DictionaryAttr getArgAttrDict(unsigned index) {
547      assert(index < $_op.getNumArguments() && "invalid argument number");
548      return ::mlir::function_interface_impl::getArgAttrDict($_op, index);
549    }
550
551    /// Returns the dictionary attribute corresponding to the result at 'index'.
552    /// If there are no result attributes at 'index', a null attribute is
553    /// returned.
554    ::mlir::DictionaryAttr getResultAttrDict(unsigned index) {
555      assert(index < $_op.getNumResults() && "invalid result number");
556      return ::mlir::function_interface_impl::getResultAttrDict($_op, index);
557    }
558  }];
559
560  let verify = "return function_interface_impl::verifyTrait(cast<ConcreteOp>($_op));";
561}
562
563#endif // MLIR_INTERFACES_FUNCTIONINTERFACES_TD_
564