Coverage Report

Created: 2020-06-26 05:44

/home/arjun/llvm-project/mlir/include/mlir/IR/FunctionSupport.h
Line
Count
Source (jump to first uncovered line)
1
//===- FunctionSupport.h - Utility types for function-like ops --*- C++ -*-===//
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 defines support types for Operations that represent function-like
10
// constructs to use.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#ifndef MLIR_IR_FUNCTIONSUPPORT_H
15
#define MLIR_IR_FUNCTIONSUPPORT_H
16
17
#include "mlir/IR/OpDefinition.h"
18
#include "llvm/ADT/SmallString.h"
19
20
namespace mlir {
21
22
namespace impl {
23
24
/// Return the name of the attribute used for function types.
25
0
inline StringRef getTypeAttrName() { return "type"; }
26
27
/// Return the name of the attribute used for function arguments.
28
0
inline StringRef getArgAttrName(unsigned arg, SmallVectorImpl<char> &out) {
29
0
  out.clear();
30
0
  return ("arg" + Twine(arg)).toStringRef(out);
31
0
}
32
33
/// Returns true if the given name is a valid argument attribute name.
34
0
inline bool isArgAttrName(StringRef name) {
35
0
  APInt unused;
36
0
  return name.startswith("arg") &&
37
0
         !name.drop_front(3).getAsInteger(/*Radix=*/10, unused);
38
0
}
39
40
/// Return the name of the attribute used for function results.
41
0
inline StringRef getResultAttrName(unsigned arg, SmallVectorImpl<char> &out) {
42
0
  out.clear();
43
0
  return ("result" + Twine(arg)).toStringRef(out);
44
0
}
45
46
/// Returns the dictionary attribute corresponding to the argument at 'index'.
47
/// If there are no argument attributes at 'index', a null attribute is
48
/// returned.
49
0
inline DictionaryAttr getArgAttrDict(Operation *op, unsigned index) {
50
0
  SmallString<8> nameOut;
51
0
  return op->getAttrOfType<DictionaryAttr>(getArgAttrName(index, nameOut));
52
0
}
53
54
/// Returns the dictionary attribute corresponding to the result at 'index'.
55
/// If there are no result attributes at 'index', a null attribute is
56
/// returned.
57
0
inline DictionaryAttr getResultAttrDict(Operation *op, unsigned index) {
58
0
  SmallString<8> nameOut;
59
0
  return op->getAttrOfType<DictionaryAttr>(getResultAttrName(index, nameOut));
60
0
}
61
62
/// Return all of the attributes for the argument at 'index'.
63
0
inline ArrayRef<NamedAttribute> getArgAttrs(Operation *op, unsigned index) {
64
0
  auto argDict = getArgAttrDict(op, index);
65
0
  return argDict ? argDict.getValue() : llvm::None;
66
0
}
67
68
/// Return all of the attributes for the result at 'index'.
69
0
inline ArrayRef<NamedAttribute> getResultAttrs(Operation *op, unsigned index) {
70
0
  auto resultDict = getResultAttrDict(op, index);
71
0
  return resultDict ? resultDict.getValue() : llvm::None;
72
0
}
73
74
} // namespace impl
75
76
namespace OpTrait {
77
78
/// This trait provides APIs for Ops that behave like functions.  In particular:
79
/// - Ops must be symbols, i.e. also have the `Symbol` trait;
80
/// - Ops have a single region with multiple blocks that corresponds to the body
81
///   of the function;
82
/// - the absence of a region corresponds to an external function;
83
/// - leading arguments of the first block of the region are treated as function
84
///   arguments;
85
/// - they can have argument attributes that are stored in a dictionary
86
///   attribute on the Op itself.
87
/// This trait does *NOT* provide type support for the functions, meaning that
88
/// concrete Ops must handle the type of the declared or defined function.
89
/// `getTypeAttrName()` is a convenience function that returns the name of the
90
/// attribute that can be used to store the function type, but the trait makes
91
/// no assumption based on it.
92
///
93
/// - Concrete ops *must* define a member function `getNumFuncArguments()` that
94
///   returns the number of function arguments based exclusively on type (so
95
///   that it can be called on function declarations).
96
/// - Concrete ops *must* define a member function `getNumFuncResults()` that
97
///   returns the number of function results based exclusively on type (so that
98
///   it can be called on function declarations).
99
/// - To verify that the type respects op-specific invariants, concrete ops may
100
///   redefine the `verifyType()` hook that will be called after verifying the
101
///   presence of the `type` attribute and before any call to
102
///   `getNumFuncArguments`/`getNumFuncResults` from the verifier.
103
/// - To verify that the body respects op-specific invariants, concrete ops may
104
///   redefine the `verifyBody()` hook that will be called after verifying the
105
///   function type and the presence of the (potentially empty) body region.
106
template <typename ConcreteType>
107
class FunctionLike : public OpTrait::TraitBase<ConcreteType, FunctionLike> {
108
public:
109
  /// Verify that all of the argument attributes are dialect attributes.
110
  static LogicalResult verifyTrait(Operation *op);
111
112
  //===--------------------------------------------------------------------===//
113
  // Body Handling
114
  //===--------------------------------------------------------------------===//
115
116
  /// Returns true if this function is external, i.e. it has no body.
117
0
  bool isExternal() { return empty(); }
118
119
0
  Region &getBody() { return this->getOperation()->getRegion(0); }
120
121
  /// Delete all blocks from this function.
122
  void eraseBody() {
123
    getBody().dropAllReferences();
124
    getBody().getBlocks().clear();
125
  }
126
127
  /// This is the list of blocks in the function.
128
  using BlockListType = Region::BlockListType;
129
0
  BlockListType &getBlocks() { return getBody().getBlocks(); }
130
131
  // Iteration over the block in the function.
132
  using iterator = BlockListType::iterator;
133
  using reverse_iterator = BlockListType::reverse_iterator;
134
135
  iterator begin() { return getBody().begin(); }
136
  iterator end() { return getBody().end(); }
137
  reverse_iterator rbegin() { return getBody().rbegin(); }
138
  reverse_iterator rend() { return getBody().rend(); }
139
140
0
  bool empty() { return getBody().empty(); }
141
  void push_back(Block *block) { getBody().push_back(block); }
142
  void push_front(Block *block) { getBody().push_front(block); }
143
144
  Block &back() { return getBody().back(); }
145
0
  Block &front() { return getBody().front(); }
146
147
  /// Add an entry block to an empty function, and set up the block arguments
148
  /// to match the signature of the function. The newly inserted entry block
149
  /// is returned.
150
  ///
151
  /// Note that the concrete class must define a method with the same name to
152
  /// hide this one if the concrete class does not use FunctionType for the
153
  /// function type under the hood.
154
  Block *addEntryBlock();
155
156
  /// Add a normal block to the end of the function's block list. The function
157
  /// should at least already have an entry block.
158
  Block *addBlock();
159
160
  /// Hook for concrete ops to verify the contents of the body. Called as a
161
  /// part of trait verification, after type verification and ensuring that a
162
  /// region exists.
163
  LogicalResult verifyBody();
164
165
  //===--------------------------------------------------------------------===//
166
  // Type Attribute Handling
167
  //===--------------------------------------------------------------------===//
168
169
  /// Return the name of the attribute used for function types.
170
0
  static StringRef getTypeAttrName() { return ::mlir::impl::getTypeAttrName(); }
171
172
0
  TypeAttr getTypeAttr() {
173
0
    return this->getOperation()->template getAttrOfType<TypeAttr>(
174
0
        getTypeAttrName());
175
0
  }
176
177
  /// Return the type of this function.
178
  ///
179
  /// Note that the concrete class must define a method with the same name to
180
  /// hide this one if the concrete class does not use FunctionType for the
181
  /// function type under the hood.
182
0
  FunctionType getType() {
183
0
    return getTypeAttr().getValue().template cast<FunctionType>();
184
0
  }
185
186
0
  bool isTypeAttrValid() {
187
0
    auto typeAttr = getTypeAttr();
188
0
    if (!typeAttr)
189
0
      return false;
190
0
    return typeAttr.getValue() != Type{};
191
0
  }
192
193
  /// Change the type of this function in place. This is an extremely dangerous
194
  /// operation and it is up to the caller to ensure that this is legal for this
195
  /// function, and to restore invariants:
196
  ///  - the entry block args must be updated to match the function params.
197
  ///  - the argument/result attributes may need an update: if the new type
198
  ///    has less parameters we drop the extra attributes, if there are more
199
  ///    parameters they won't have any attributes.
200
  ///
201
  /// Note that the concrete class must define a method with the same name to
202
  /// hide this one if the concrete class does not use FunctionType for the
203
  /// function type under the hood.
204
  void setType(FunctionType newType);
205
206
  //===--------------------------------------------------------------------===//
207
  // Argument Handling
208
  //===--------------------------------------------------------------------===//
209
210
0
  unsigned getNumArguments() {
211
0
    return static_cast<ConcreteType *>(this)->getNumFuncArguments();
212
0
  }
213
214
0
  unsigned getNumResults() {
215
0
    return static_cast<ConcreteType *>(this)->getNumFuncResults();
216
0
  }
217
218
  /// Gets argument.
219
0
  BlockArgument getArgument(unsigned idx) {
220
0
    return getBlocks().front().getArgument(idx);
221
0
  }
222
223
  /// Support argument iteration.
224
  using args_iterator = Block::args_iterator;
225
  args_iterator args_begin() { return front().args_begin(); }
226
  args_iterator args_end() { return front().args_end(); }
227
  Block::BlockArgListType getArguments() { return front().getArguments(); }
228
229
  //===--------------------------------------------------------------------===//
230
  // Argument Attributes
231
  //===--------------------------------------------------------------------===//
232
233
  /// FunctionLike operations allow for attaching attributes to each of the
234
  /// respective function arguments. These argument attributes are stored as
235
  /// DictionaryAttrs in the main operation attribute dictionary. The name of
236
  /// these entries is `arg` followed by the index of the argument. These
237
  /// argument attribute dictionaries are optional, and will generally only
238
  /// exist if they are non-empty.
239
240
  /// Return all of the attributes for the argument at 'index'.
241
0
  ArrayRef<NamedAttribute> getArgAttrs(unsigned index) {
242
0
    return ::mlir::impl::getArgAttrs(this->getOperation(), index);
243
0
  }
244
245
  /// Return all argument attributes of this function.
246
  void getAllArgAttrs(SmallVectorImpl<MutableDictionaryAttr> &result) {
247
    for (unsigned i = 0, e = getNumArguments(); i != e; ++i)
248
      result.emplace_back(getArgAttrDict(i));
249
  }
250
251
  /// Return the specified attribute, if present, for the argument at 'index',
252
  /// null otherwise.
253
  Attribute getArgAttr(unsigned index, Identifier name) {
254
    auto argDict = getArgAttrDict(index);
255
    return argDict ? argDict.get(name) : nullptr;
256
  }
257
  Attribute getArgAttr(unsigned index, StringRef name) {
258
    auto argDict = getArgAttrDict(index);
259
    return argDict ? argDict.get(name) : nullptr;
260
  }
261
262
  template <typename AttrClass>
263
  AttrClass getArgAttrOfType(unsigned index, Identifier name) {
264
    return getArgAttr(index, name).template dyn_cast_or_null<AttrClass>();
265
  }
266
  template <typename AttrClass>
267
  AttrClass getArgAttrOfType(unsigned index, StringRef name) {
268
    return getArgAttr(index, name).template dyn_cast_or_null<AttrClass>();
269
  }
270
271
  /// Set the attributes held by the argument at 'index'.
272
  void setArgAttrs(unsigned index, ArrayRef<NamedAttribute> attributes);
273
  void setArgAttrs(unsigned index, MutableDictionaryAttr attributes);
274
0
  void setAllArgAttrs(ArrayRef<MutableDictionaryAttr> attributes) {
275
0
    assert(attributes.size() == getNumArguments());
276
0
    for (unsigned i = 0, e = attributes.size(); i != e; ++i)
277
0
      setArgAttrs(i, attributes[i]);
278
0
  }
279
280
  /// If the an attribute exists with the specified name, change it to the new
281
  /// value. Otherwise, add a new attribute with the specified name/value.
282
  void setArgAttr(unsigned index, Identifier name, Attribute value);
283
  void setArgAttr(unsigned index, StringRef name, Attribute value) {
284
    setArgAttr(index, Identifier::get(name, this->getOperation()->getContext()),
285
               value);
286
  }
287
288
  /// Remove the attribute 'name' from the argument at 'index'.
289
  MutableDictionaryAttr::RemoveResult removeArgAttr(unsigned index,
290
                                                    Identifier name);
291
292
  //===--------------------------------------------------------------------===//
293
  // Result Attributes
294
  //===--------------------------------------------------------------------===//
295
296
  /// FunctionLike operations allow for attaching attributes to each of the
297
  /// respective function results. These result attributes are stored as
298
  /// DictionaryAttrs in the main operation attribute dictionary. The name of
299
  /// these entries is `result` followed by the index of the result. These
300
  /// result attribute dictionaries are optional, and will generally only
301
  /// exist if they are non-empty.
302
303
  /// Return all of the attributes for the result at 'index'.
304
0
  ArrayRef<NamedAttribute> getResultAttrs(unsigned index) {
305
0
    return ::mlir::impl::getResultAttrs(this->getOperation(), index);
306
0
  }
307
308
  /// Return all result attributes of this function.
309
  void getAllResultAttrs(SmallVectorImpl<MutableDictionaryAttr> &result) {
310
    for (unsigned i = 0, e = getNumResults(); i != e; ++i)
311
      result.emplace_back(getResultAttrDict(i));
312
  }
313
314
  /// Return the specified attribute, if present, for the result at 'index',
315
  /// null otherwise.
316
  Attribute getResultAttr(unsigned index, Identifier name) {
317
    auto argDict = getResultAttrDict(index);
318
    return argDict ? argDict.get(name) : nullptr;
319
  }
320
  Attribute getResultAttr(unsigned index, StringRef name) {
321
    auto argDict = getResultAttrDict(index);
322
    return argDict ? argDict.get(name) : nullptr;
323
  }
324
325
  template <typename AttrClass>
326
  AttrClass getResultAttrOfType(unsigned index, Identifier name) {
327
    return getResultAttr(index, name).template dyn_cast_or_null<AttrClass>();
328
  }
329
  template <typename AttrClass>
330
  AttrClass getResultAttrOfType(unsigned index, StringRef name) {
331
    return getResultAttr(index, name).template dyn_cast_or_null<AttrClass>();
332
  }
333
334
  /// Set the attributes held by the result at 'index'.
335
  void setResultAttrs(unsigned index, ArrayRef<NamedAttribute> attributes);
336
  void setResultAttrs(unsigned index, MutableDictionaryAttr attributes);
337
  void setAllResultAttrs(ArrayRef<MutableDictionaryAttr> attributes) {
338
    assert(attributes.size() == getNumResults());
339
    for (unsigned i = 0, e = attributes.size(); i != e; ++i)
340
      setResultAttrs(i, attributes[i]);
341
  }
342
343
  /// If the an attribute exists with the specified name, change it to the new
344
  /// value. Otherwise, add a new attribute with the specified name/value.
345
  void setResultAttr(unsigned index, Identifier name, Attribute value);
346
  void setResultAttr(unsigned index, StringRef name, Attribute value) {
347
    setResultAttr(index,
348
                  Identifier::get(name, this->getOperation()->getContext()),
349
                  value);
350
  }
351
352
  /// Remove the attribute 'name' from the result at 'index'.
353
  MutableDictionaryAttr::RemoveResult removeResultAttr(unsigned index,
354
                                                       Identifier name);
355
356
protected:
357
  /// Returns the attribute entry name for the set of argument attributes at
358
  /// 'index'.
359
0
  static StringRef getArgAttrName(unsigned index, SmallVectorImpl<char> &out) {
360
0
    return ::mlir::impl::getArgAttrName(index, out);
361
0
  }
362
363
  /// Returns the dictionary attribute corresponding to the argument at 'index'.
364
  /// If there are no argument attributes at 'index', a null attribute is
365
  /// returned.
366
0
  DictionaryAttr getArgAttrDict(unsigned index) {
367
0
    assert(index < getNumArguments() && "invalid argument number");
368
0
    return ::mlir::impl::getArgAttrDict(this->getOperation(), index);
369
0
  }
370
371
  /// Returns the attribute entry name for the set of result attributes at
372
  /// 'index'.
373
  static StringRef getResultAttrName(unsigned index,
374
0
                                     SmallVectorImpl<char> &out) {
375
0
    return ::mlir::impl::getResultAttrName(index, out);
376
0
  }
377
378
  /// Returns the dictionary attribute corresponding to the result at 'index'.
379
  /// If there are no result attributes at 'index', a null attribute is
380
  /// returned.
381
  DictionaryAttr getResultAttrDict(unsigned index) {
382
    assert(index < getNumResults() && "invalid result number");
383
    return ::mlir::impl::getResultAttrDict(this->getOperation(), index);
384
  }
385
386
  /// Hook for concrete classes to verify that the type attribute respects
387
  /// op-specific invariants.  Default implementation always succeeds.
388
  LogicalResult verifyType() { return success(); }
389
};
390
391
/// Default verifier checks that if the entry block exists, it has the same
392
/// number of arguments as the function-like operation.
393
template <typename ConcreteType>
394
0
LogicalResult FunctionLike<ConcreteType>::verifyBody() {
395
0
  auto funcOp = cast<ConcreteType>(this->getOperation());
396
0
397
0
  if (funcOp.isExternal())
398
0
    return success();
399
0
400
0
  unsigned numArguments = funcOp.getNumArguments();
401
0
  if (funcOp.front().getNumArguments() != numArguments)
402
0
    return funcOp.emitOpError("entry block must have ")
403
0
           << numArguments << " arguments to match function signature";
404
0
405
0
  return success();
406
0
}
407
408
template <typename ConcreteType>
409
0
LogicalResult FunctionLike<ConcreteType>::verifyTrait(Operation *op) {
410
0
  MLIRContext *ctx = op->getContext();
411
0
  auto funcOp = cast<ConcreteType>(op);
412
0
413
0
  if (!funcOp.isTypeAttrValid())
414
0
    return funcOp.emitOpError("requires a type attribute '")
415
0
           << getTypeAttrName() << '\'';
416
0
417
0
  if (failed(funcOp.verifyType()))
418
0
    return failure();
419
0
420
0
  for (unsigned i = 0, e = funcOp.getNumArguments(); i != e; ++i) {
421
0
    // Verify that all of the argument attributes are dialect attributes, i.e.
422
0
    // that they contain a dialect prefix in their name.  Call the dialect, if
423
0
    // registered, to verify the attributes themselves.
424
0
    for (auto attr : funcOp.getArgAttrs(i)) {
425
0
      if (!attr.first.strref().contains('.'))
426
0
        return funcOp.emitOpError("arguments may only have dialect attributes");
427
0
      auto dialectNamePair = attr.first.strref().split('.');
428
0
      if (auto *dialect = ctx->getRegisteredDialect(dialectNamePair.first)) {
429
0
        if (failed(dialect->verifyRegionArgAttribute(op, /*regionIndex=*/0,
430
0
                                                     /*argIndex=*/i, attr)))
431
0
          return failure();
432
0
      }
433
0
    }
434
0
  }
435
0
436
0
  for (unsigned i = 0, e = funcOp.getNumResults(); i != e; ++i) {
437
0
    // Verify that all of the result attributes are dialect attributes, i.e.
438
0
    // that they contain a dialect prefix in their name.  Call the dialect, if
439
0
    // registered, to verify the attributes themselves.
440
0
    for (auto attr : funcOp.getResultAttrs(i)) {
441
0
      if (!attr.first.strref().contains('.'))
442
0
        return funcOp.emitOpError("results may only have dialect attributes");
443
0
      auto dialectNamePair = attr.first.strref().split('.');
444
0
      if (auto *dialect = ctx->getRegisteredDialect(dialectNamePair.first)) {
445
0
        if (failed(dialect->verifyRegionResultAttribute(op, /*regionIndex=*/0,
446
0
                                                        /*resultIndex=*/i,
447
0
                                                        attr)))
448
0
          return failure();
449
0
      }
450
0
    }
451
0
  }
452
0
453
0
  // Check that the op has exactly one region for the body.
454
0
  if (op->getNumRegions() != 1)
455
0
    return funcOp.emitOpError("expects one region");
456
0
457
0
  return funcOp.verifyBody();
458
0
}
459
460
//===----------------------------------------------------------------------===//
461
// Function Body.
462
//===----------------------------------------------------------------------===//
463
464
template <typename ConcreteType>
465
Block *FunctionLike<ConcreteType>::addEntryBlock() {
466
  assert(empty() && "function already has an entry block");
467
  auto *entry = new Block();
468
  push_back(entry);
469
  entry->addArguments(getType().getInputs());
470
  return entry;
471
}
472
473
template <typename ConcreteType>
474
Block *FunctionLike<ConcreteType>::addBlock() {
475
  assert(!empty() && "function should at least have an entry block");
476
  push_back(new Block());
477
  return &back();
478
}
479
480
//===----------------------------------------------------------------------===//
481
// Function Type Attribute.
482
//===----------------------------------------------------------------------===//
483
484
template <typename ConcreteType>
485
0
void FunctionLike<ConcreteType>::setType(FunctionType newType) {
486
0
  SmallVector<char, 16> nameBuf;
487
0
  auto oldType = getType();
488
0
  auto *concreteOp = static_cast<ConcreteType *>(this);
489
0
490
0
  for (int i = newType.getNumInputs(), e = oldType.getNumInputs(); i < e; i++)
491
0
    concreteOp->removeAttr(getArgAttrName(i, nameBuf));
492
0
  for (int i = newType.getNumResults(), e = oldType.getNumResults(); i < e; i++)
493
0
    concreteOp->removeAttr(getResultAttrName(i, nameBuf));
494
0
  concreteOp->setAttr(getTypeAttrName(), TypeAttr::get(newType));
495
0
}
496
497
//===----------------------------------------------------------------------===//
498
// Function Argument Attribute.
499
//===----------------------------------------------------------------------===//
500
501
/// Set the attributes held by the argument at 'index'.
502
template <typename ConcreteType>
503
void FunctionLike<ConcreteType>::setArgAttrs(
504
0
    unsigned index, ArrayRef<NamedAttribute> attributes) {
505
0
  assert(index < getNumArguments() && "invalid argument number");
506
0
  SmallString<8> nameOut;
507
0
  getArgAttrName(index, nameOut);
508
0
509
0
  if (attributes.empty())
510
0
    return (void)static_cast<ConcreteType *>(this)->removeAttr(nameOut);
511
0
  Operation *op = this->getOperation();
512
0
  op->setAttr(nameOut, DictionaryAttr::get(attributes, op->getContext()));
513
0
}
514
515
template <typename ConcreteType>
516
void FunctionLike<ConcreteType>::setArgAttrs(unsigned index,
517
0
                                             MutableDictionaryAttr attributes) {
518
0
  assert(index < getNumArguments() && "invalid argument number");
519
0
  SmallString<8> nameOut;
520
0
  if (attributes.getAttrs().empty()) {
521
0
    this->getOperation()->removeAttr(getArgAttrName(index, nameOut));
522
0
  } else {
523
0
    auto newAttr = attributes.getDictionary(
524
0
        attributes.getAttrs().front().second.getContext());
525
0
    return this->getOperation()->setAttr(getArgAttrName(index, nameOut),
526
0
                                         newAttr);
527
0
  }
528
0
}
529
530
/// If the an attribute exists with the specified name, change it to the new
531
/// value. Otherwise, add a new attribute with the specified name/value.
532
template <typename ConcreteType>
533
void FunctionLike<ConcreteType>::setArgAttr(unsigned index, Identifier name,
534
                                            Attribute value) {
535
  auto curAttr = getArgAttrDict(index);
536
  MutableDictionaryAttr attrDict(curAttr);
537
  attrDict.set(name, value);
538
539
  // If the attribute changed, then set the new arg attribute list.
540
  if (curAttr != attrDict.getDictionary(value.getContext()))
541
    setArgAttrs(index, attrDict);
542
}
543
544
/// Remove the attribute 'name' from the argument at 'index'.
545
template <typename ConcreteType>
546
MutableDictionaryAttr::RemoveResult
547
FunctionLike<ConcreteType>::removeArgAttr(unsigned index, Identifier name) {
548
  // Build an attribute list and remove the attribute at 'name'.
549
  MutableDictionaryAttr attrDict(getArgAttrDict(index));
550
  auto result = attrDict.remove(name);
551
552
  // If the attribute was removed, then update the argument dictionary.
553
  if (result == MutableDictionaryAttr::RemoveResult::Removed)
554
    setArgAttrs(index, attrDict);
555
  return result;
556
}
557
558
//===----------------------------------------------------------------------===//
559
// Function Result Attribute.
560
//===----------------------------------------------------------------------===//
561
562
/// Set the attributes held by the result at 'index'.
563
template <typename ConcreteType>
564
void FunctionLike<ConcreteType>::setResultAttrs(
565
    unsigned index, ArrayRef<NamedAttribute> attributes) {
566
  assert(index < getNumResults() && "invalid result number");
567
  SmallString<8> nameOut;
568
  getResultAttrName(index, nameOut);
569
570
  if (attributes.empty())
571
    return (void)this->getOperation()->removeAttr(nameOut);
572
  Operation *op = this->getOperation();
573
  op->setAttr(nameOut, DictionaryAttr::get(attributes, op->getContext()));
574
}
575
576
template <typename ConcreteType>
577
void FunctionLike<ConcreteType>::setResultAttrs(
578
    unsigned index, MutableDictionaryAttr attributes) {
579
  assert(index < getNumResults() && "invalid result number");
580
  SmallString<8> nameOut;
581
  if (attributes.empty()) {
582
    this->getOperation()->removeAttr(getResultAttrName(index, nameOut));
583
  } else {
584
    auto newAttr = attributes.getDictionary(this->getOperation()->getContext());
585
    return this->getOperation()->setAttr(getResultAttrName(index, nameOut),
586
                                         newAttr);
587
  }
588
}
589
590
/// If the an attribute exists with the specified name, change it to the new
591
/// value. Otherwise, add a new attribute with the specified name/value.
592
template <typename ConcreteType>
593
void FunctionLike<ConcreteType>::setResultAttr(unsigned index, Identifier name,
594
                                               Attribute value) {
595
  auto curAttr = getResultAttrDict(index);
596
  MutableDictionaryAttr attrDict(curAttr);
597
  attrDict.set(name, value);
598
599
  // If the attribute changed, then set the new arg attribute list.
600
  if (curAttr != attrDict.getDictionary(value.getContext()))
601
    setResultAttrs(index, attrDict);
602
}
603
604
/// Remove the attribute 'name' from the result at 'index'.
605
template <typename ConcreteType>
606
MutableDictionaryAttr::RemoveResult
607
FunctionLike<ConcreteType>::removeResultAttr(unsigned index, Identifier name) {
608
  // Build an attribute list and remove the attribute at 'name'.
609
  MutableDictionaryAttr attrDict(getResultAttrDict(index));
610
  auto result = attrDict.remove(name);
611
612
  // If the attribute was removed, then update the result dictionary.
613
  if (result == MutableDictionaryAttr::RemoveResult::Removed)
614
    setResultAttrs(index, attrDict);
615
  return result;
616
}
617
618
} // end namespace OpTrait
619
620
} // end namespace mlir
621
622
#endif // MLIR_IR_FUNCTIONSUPPORT_H