1//===- Operation.h - MLIR Operation Class -----------------------*- 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 the Operation class.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_IR_OPERATION_H
14#define MLIR_IR_OPERATION_H
15
16#include "mlir/IR/Block.h"
17#include "mlir/IR/BuiltinAttributes.h"
18#include "mlir/IR/Diagnostics.h"
19#include "mlir/IR/OperationSupport.h"
20#include "mlir/IR/Region.h"
21#include "llvm/ADT/Twine.h"
22#include <optional>
23
24namespace mlir {
25namespace detail {
26/// This is a "tag" used for mapping the properties storage in
27/// llvm::TrailingObjects.
28enum class OpProperties : char {};
29} // namespace detail
30
31/// Operation is the basic unit of execution within MLIR.
32///
33/// The following documentation are recommended to understand this class:
34/// - https://mlir.llvm.org/docs/LangRef/#operations
35/// - https://mlir.llvm.org/docs/Tutorials/UnderstandingTheIRStructure/
36///
37/// An Operation is defined first by its name, which is a unique string. The
38/// name is interpreted so that if it contains a '.' character, the part before
39/// is the dialect name this operation belongs to, and everything that follows
40/// is this operation name within the dialect.
41///
42/// An Operation defines zero or more SSA `Value` that we refer to as the
43/// Operation results. This array of Value is actually stored in memory before
44/// the Operation itself in reverse order. That is for an Operation with 3
45/// results we allocate the following memory layout:
46///
47/// [Result2, Result1, Result0, Operation]
48/// ^ this is where `Operation*` pointer points to.
49///
50/// A consequence of this is that this class must be heap allocated, which is
51/// handled by the various `create` methods. Each result contains:
52/// - one pointer to the first use (see `OpOperand`)
53/// - the type of the SSA Value this result defines.
54/// - the index for this result in the array.
55/// The results are defined as subclass of `ValueImpl`, and more precisely as
56/// the only two subclasses of `OpResultImpl`: `InlineOpResult` and
57/// `OutOfLineOpResult`. The former is used for the first 5 results and the
58/// latter for the subsequent ones. They differ in how they store their index:
59/// the first 5 results only need 3 bits and thus are packed with the Type
60/// pointer, while the subsequent one have an extra `unsigned` value and thus
61/// need more space.
62///
63/// An Operation also has zero or more operands: these are uses of SSA Value,
64/// which can be the results of other operations or Block arguments. Each of
65/// these uses is an instance of `OpOperand`. This optional array is initially
66/// tail allocated with the operation class itself, but can be dynamically moved
67/// out-of-line in a dynamic allocation as needed.
68///
69/// An Operation may contain optionally one or multiple Regions, stored in a
70/// tail allocated array. Each `Region` is a list of Blocks. Each `Block` is
71/// itself a list of Operations. This structure is effectively forming a tree.
72///
73/// Some operations like branches also refer to other Block, in which case they
74/// would have an array of `BlockOperand`.
75///
76/// An Operation may contain optionally a "Properties" object: this is a
77/// pre-defined C++ object with a fixed size. This object is owned by the
78/// operation and deleted with the operation. It can be converted to an
79/// Attribute on demand, or loaded from an Attribute.
80///
81///
82/// Finally an Operation also contain an optional `DictionaryAttr`, a Location,
83/// and a pointer to its parent Block (if any).
84class alignas(8) Operation final
85 : public llvm::ilist_node_with_parent<Operation, Block>,
86 private llvm::TrailingObjects<Operation, detail::OperandStorage,
87 detail::OpProperties, BlockOperand, Region,
88 OpOperand> {
89public:
90 /// Create a new Operation with the specific fields. This constructor
91 /// populates the provided attribute list with default attributes if
92 /// necessary.
93 static Operation *create(Location location, OperationName name,
94 TypeRange resultTypes, ValueRange operands,
95 NamedAttrList &&attributes,
96 OpaqueProperties properties, BlockRange successors,
97 unsigned numRegions);
98
99 /// Create a new Operation with the specific fields. This constructor uses an
100 /// existing attribute dictionary to avoid uniquing a list of attributes.
101 static Operation *create(Location location, OperationName name,
102 TypeRange resultTypes, ValueRange operands,
103 DictionaryAttr attributes,
104 OpaqueProperties properties, BlockRange successors,
105 unsigned numRegions);
106
107 /// Create a new Operation from the fields stored in `state`.
108 static Operation *create(const OperationState &state);
109
110 /// Create a new Operation with the specific fields.
111 static Operation *create(Location location, OperationName name,
112 TypeRange resultTypes, ValueRange operands,
113 NamedAttrList &&attributes,
114 OpaqueProperties properties,
115 BlockRange successors = {},
116 RegionRange regions = {});
117
118 /// The name of an operation is the key identifier for it.
119 OperationName getName() { return name; }
120
121 /// If this operation has a registered operation description, return it.
122 /// Otherwise return std::nullopt.
123 std::optional<RegisteredOperationName> getRegisteredInfo() {
124 return getName().getRegisteredInfo();
125 }
126
127 /// Returns true if this operation has a registered operation description,
128 /// otherwise false.
129 bool isRegistered() { return getName().isRegistered(); }
130
131 /// Remove this operation from its parent block and delete it.
132 void erase();
133
134 /// Remove the operation from its parent block, but don't delete it.
135 void remove();
136
137 /// Class encompassing various options related to cloning an operation. Users
138 /// of this class should pass it to Operation's 'clone' methods.
139 /// Current options include:
140 /// * Whether cloning should recursively traverse into the regions of the
141 /// operation or not.
142 /// * Whether cloning should also clone the operands of the operation.
143 class CloneOptions {
144 public:
145 /// Default constructs an option with all flags set to false. That means all
146 /// parts of an operation that may optionally not be cloned, are not cloned.
147 CloneOptions();
148
149 /// Constructs an instance with the clone regions and clone operands flags
150 /// set accordingly.
151 CloneOptions(bool cloneRegions, bool cloneOperands);
152
153 /// Returns an instance with all flags set to true. This is the default
154 /// when using the clone method and clones all parts of the operation.
155 static CloneOptions all();
156
157 /// Configures whether cloning should traverse into any of the regions of
158 /// the operation. If set to true, the operation's regions are recursively
159 /// cloned. If set to false, cloned operations will have the same number of
160 /// regions, but they will be empty.
161 /// Cloning of nested operations in the operation's regions are currently
162 /// unaffected by other flags.
163 CloneOptions &cloneRegions(bool enable = true);
164
165 /// Returns whether regions of the operation should be cloned as well.
166 bool shouldCloneRegions() const { return cloneRegionsFlag; }
167
168 /// Configures whether operation' operands should be cloned. Otherwise the
169 /// resulting clones will simply have zero operands.
170 CloneOptions &cloneOperands(bool enable = true);
171
172 /// Returns whether operands should be cloned as well.
173 bool shouldCloneOperands() const { return cloneOperandsFlag; }
174
175 private:
176 /// Whether regions should be cloned.
177 bool cloneRegionsFlag : 1;
178 /// Whether operands should be cloned.
179 bool cloneOperandsFlag : 1;
180 };
181
182 /// Create a deep copy of this operation, remapping any operands that use
183 /// values outside of the operation using the map that is provided (leaving
184 /// them alone if no entry is present). Replaces references to cloned
185 /// sub-operations to the corresponding operation that is copied, and adds
186 /// those mappings to the map.
187 /// Optionally, one may configure what parts of the operation to clone using
188 /// the options parameter.
189 ///
190 /// Calling this method from multiple threads is generally safe if through the
191 /// process of cloning no new uses of 'Value's from outside the operation are
192 /// created. Cloning an isolated-from-above operation with no operands, such
193 /// as top level function operations, is therefore always safe. Using the
194 /// mapper, it is possible to avoid adding uses to outside operands by
195 /// remapping them to 'Value's owned by the caller thread.
196 Operation *clone(IRMapping &mapper,
197 CloneOptions options = CloneOptions::all());
198 Operation *clone(CloneOptions options = CloneOptions::all());
199
200 /// Create a partial copy of this operation without traversing into attached
201 /// regions. The new operation will have the same number of regions as the
202 /// original one, but they will be left empty.
203 /// Operands are remapped using `mapper` (if present), and `mapper` is updated
204 /// to contain the results.
205 Operation *cloneWithoutRegions(IRMapping &mapper);
206
207 /// Create a partial copy of this operation without traversing into attached
208 /// regions. The new operation will have the same number of regions as the
209 /// original one, but they will be left empty.
210 Operation *cloneWithoutRegions();
211
212 /// Returns the operation block that contains this operation.
213 Block *getBlock() { return block; }
214
215 /// Return the context this operation is associated with.
216 MLIRContext *getContext() { return location->getContext(); }
217
218 /// Return the dialect this operation is associated with, or nullptr if the
219 /// associated dialect is not loaded.
220 Dialect *getDialect() { return getName().getDialect(); }
221
222 /// The source location the operation was defined or derived from.
223 Location getLoc() { return location; }
224
225 /// Set the source location the operation was defined or derived from.
226 void setLoc(Location loc) { location = loc; }
227
228 /// Returns the region to which the instruction belongs. Returns nullptr if
229 /// the instruction is unlinked.
230 Region *getParentRegion() { return block ? block->getParent() : nullptr; }
231
232 /// Returns the closest surrounding operation that contains this operation
233 /// or nullptr if this is a top-level operation.
234 Operation *getParentOp() { return block ? block->getParentOp() : nullptr; }
235
236 /// Return the closest surrounding parent operation that is of type 'OpTy'.
237 template <typename OpTy>
238 OpTy getParentOfType() {
239 auto *op = this;
240 while ((op = op->getParentOp()))
241 if (auto parentOp = dyn_cast<OpTy>(op))
242 return parentOp;
243 return OpTy();
244 }
245
246 /// Returns the closest surrounding parent operation with trait `Trait`.
247 template <template <typename T> class Trait>
248 Operation *getParentWithTrait() {
249 Operation *op = this;
250 while ((op = op->getParentOp()))
251 if (op->hasTrait<Trait>())
252 return op;
253 return nullptr;
254 }
255
256 /// Return true if this operation is a proper ancestor of the `other`
257 /// operation.
258 bool isProperAncestor(Operation *other);
259
260 /// Return true if this operation is an ancestor of the `other` operation. An
261 /// operation is considered as its own ancestor, use `isProperAncestor` to
262 /// avoid this.
263 bool isAncestor(Operation *other) {
264 return this == other || isProperAncestor(other);
265 }
266
267 /// Replace any uses of 'from' with 'to' within this operation.
268 void replaceUsesOfWith(Value from, Value to);
269
270 /// Replace all uses of results of this operation with the provided 'values'.
271 template <typename ValuesT>
272 void replaceAllUsesWith(ValuesT &&values) {
273 getResults().replaceAllUsesWith(std::forward<ValuesT>(values));
274 }
275
276 /// Replace uses of results of this operation with the provided `values` if
277 /// the given callback returns true.
278 template <typename ValuesT>
279 void replaceUsesWithIf(ValuesT &&values,
280 function_ref<bool(OpOperand &)> shouldReplace) {
281 getResults().replaceUsesWithIf(std::forward<ValuesT>(values),
282 shouldReplace);
283 }
284
285 /// Destroys this operation and its subclass data.
286 void destroy();
287
288 /// This drops all operand uses from this operation, which is an essential
289 /// step in breaking cyclic dependences between references when they are to
290 /// be deleted.
291 void dropAllReferences();
292
293 /// Drop uses of all values defined by this operation or its nested regions.
294 void dropAllDefinedValueUses();
295
296 /// Unlink this operation from its current block and insert it right before
297 /// `existingOp` which may be in the same or another block in the same
298 /// function.
299 void moveBefore(Operation *existingOp);
300
301 /// Unlink this operation from its current block and insert it right before
302 /// `iterator` in the specified block.
303 void moveBefore(Block *block, llvm::iplist<Operation>::iterator iterator);
304
305 /// Unlink this operation from its current block and insert it right after
306 /// `existingOp` which may be in the same or another block in the same
307 /// function.
308 void moveAfter(Operation *existingOp);
309
310 /// Unlink this operation from its current block and insert it right after
311 /// `iterator` in the specified block.
312 void moveAfter(Block *block, llvm::iplist<Operation>::iterator iterator);
313
314 /// Given an operation 'other' that is within the same parent block, return
315 /// whether the current operation is before 'other' in the operation list
316 /// of the parent block.
317 /// Note: This function has an average complexity of O(1), but worst case may
318 /// take O(N) where N is the number of operations within the parent block.
319 bool isBeforeInBlock(Operation *other);
320
321 void print(raw_ostream &os, const OpPrintingFlags &flags = std::nullopt);
322 void print(raw_ostream &os, AsmState &state);
323 void dump();
324
325 //===--------------------------------------------------------------------===//
326 // Operands
327 //===--------------------------------------------------------------------===//
328
329 /// Replace the current operands of this operation with the ones provided in
330 /// 'operands'.
331 void setOperands(ValueRange operands);
332
333 /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
334 /// with the ones provided in 'operands'. 'operands' may be smaller or larger
335 /// than the range pointed to by 'start'+'length'.
336 void setOperands(unsigned start, unsigned length, ValueRange operands);
337
338 /// Insert the given operands into the operand list at the given 'index'.
339 void insertOperands(unsigned index, ValueRange operands);
340
341 unsigned getNumOperands() {
342 return LLVM_LIKELY(hasOperandStorage) ? getOperandStorage().size() : 0;
343 }
344
345 Value getOperand(unsigned idx) { return getOpOperand(idx).get(); }
346 void setOperand(unsigned idx, Value value) {
347 return getOpOperand(idx).set(value);
348 }
349
350 /// Erase the operand at position `idx`.
351 void eraseOperand(unsigned idx) { eraseOperands(idx); }
352
353 /// Erase the operands starting at position `idx` and ending at position
354 /// 'idx'+'length'.
355 void eraseOperands(unsigned idx, unsigned length = 1) {
356 getOperandStorage().eraseOperands(start: idx, length);
357 }
358
359 /// Erases the operands that have their corresponding bit set in
360 /// `eraseIndices` and removes them from the operand list.
361 void eraseOperands(const BitVector &eraseIndices) {
362 getOperandStorage().eraseOperands(eraseIndices);
363 }
364
365 // Support operand iteration.
366 using operand_range = OperandRange;
367 using operand_iterator = operand_range::iterator;
368
369 operand_iterator operand_begin() { return getOperands().begin(); }
370 operand_iterator operand_end() { return getOperands().end(); }
371
372 /// Returns an iterator on the underlying Value's.
373 operand_range getOperands() {
374 MutableArrayRef<OpOperand> operands = getOpOperands();
375 return OperandRange(operands.data(), operands.size());
376 }
377
378 MutableArrayRef<OpOperand> getOpOperands() {
379 return LLVM_LIKELY(hasOperandStorage) ? getOperandStorage().getOperands()
380 : MutableArrayRef<OpOperand>();
381 }
382
383 OpOperand &getOpOperand(unsigned idx) {
384 return getOperandStorage().getOperands()[idx];
385 }
386
387 // Support operand type iteration.
388 using operand_type_iterator = operand_range::type_iterator;
389 using operand_type_range = operand_range::type_range;
390 operand_type_iterator operand_type_begin() { return operand_begin(); }
391 operand_type_iterator operand_type_end() { return operand_end(); }
392 operand_type_range getOperandTypes() { return getOperands().getTypes(); }
393
394 //===--------------------------------------------------------------------===//
395 // Results
396 //===--------------------------------------------------------------------===//
397
398 /// Return the number of results held by this operation.
399 unsigned getNumResults() { return numResults; }
400
401 /// Get the 'idx'th result of this operation.
402 OpResult getResult(unsigned idx) { return OpResult(getOpResultImpl(resultNumber: idx)); }
403
404 /// Support result iteration.
405 using result_range = ResultRange;
406 using result_iterator = result_range::iterator;
407
408 result_iterator result_begin() { return getResults().begin(); }
409 result_iterator result_end() { return getResults().end(); }
410 result_range getResults() {
411 return numResults == 0 ? result_range(nullptr, 0)
412 : result_range(getInlineOpResult(resultNumber: 0), numResults);
413 }
414
415 result_range getOpResults() { return getResults(); }
416 OpResult getOpResult(unsigned idx) { return getResult(idx); }
417
418 /// Support result type iteration.
419 using result_type_iterator = result_range::type_iterator;
420 using result_type_range = result_range::type_range;
421 result_type_iterator result_type_begin() { return getResultTypes().begin(); }
422 result_type_iterator result_type_end() { return getResultTypes().end(); }
423 result_type_range getResultTypes() { return getResults().getTypes(); }
424
425 //===--------------------------------------------------------------------===//
426 // Attributes
427 //===--------------------------------------------------------------------===//
428
429 // Operations may optionally carry a list of attributes that associate
430 // constants to names. Attributes may be dynamically added and removed over
431 // the lifetime of an operation.
432
433 /// Access an inherent attribute by name: returns an empty optional if there
434 /// is no inherent attribute with this name.
435 ///
436 /// This method is available as a transient facility in the migration process
437 /// to use Properties instead.
438 std::optional<Attribute> getInherentAttr(StringRef name);
439
440 /// Set an inherent attribute by name.
441 ///
442 /// This method is available as a transient facility in the migration process
443 /// to use Properties instead.
444 void setInherentAttr(StringAttr name, Attribute value);
445
446 /// Access a discardable attribute by name, returns an null Attribute if the
447 /// discardable attribute does not exist.
448 Attribute getDiscardableAttr(StringRef name) { return attrs.get(name); }
449
450 /// Access a discardable attribute by name, returns an null Attribute if the
451 /// discardable attribute does not exist.
452 Attribute getDiscardableAttr(StringAttr name) { return attrs.get(name); }
453
454 /// Set a discardable attribute by name.
455 void setDiscardableAttr(StringAttr name, Attribute value) {
456 NamedAttrList attributes(attrs);
457 if (attributes.set(name, value) != value)
458 attrs = attributes.getDictionary(getContext());
459 }
460 void setDiscardableAttr(StringRef name, Attribute value) {
461 setDiscardableAttr(StringAttr::get(getContext(), name), value);
462 }
463
464 /// Remove the discardable attribute with the specified name if it exists.
465 /// Return the attribute that was erased, or nullptr if there was no attribute
466 /// with such name.
467 Attribute removeDiscardableAttr(StringAttr name) {
468 NamedAttrList attributes(attrs);
469 Attribute removedAttr = attributes.erase(name);
470 if (removedAttr)
471 attrs = attributes.getDictionary(getContext());
472 return removedAttr;
473 }
474 Attribute removeDiscardableAttr(StringRef name) {
475 return removeDiscardableAttr(StringAttr::get(getContext(), name));
476 }
477
478 /// Return a range of all of discardable attributes on this operation. Note
479 /// that for unregistered operations that are not storing inherent attributes
480 /// as properties, all attributes are considered discardable.
481 auto getDiscardableAttrs() {
482 std::optional<RegisteredOperationName> opName = getRegisteredInfo();
483 ArrayRef<StringAttr> attributeNames =
484 opName ? getRegisteredInfo()->getAttributeNames()
485 : ArrayRef<StringAttr>();
486 return llvm::make_filter_range(
487 attrs.getValue(),
488 [this, attributeNames](const NamedAttribute attribute) {
489 return getPropertiesStorage() ||
490 !llvm::is_contained(attributeNames, attribute.getName());
491 });
492 }
493
494 /// Return all of the discardable attributes on this operation as a
495 /// DictionaryAttr.
496 DictionaryAttr getDiscardableAttrDictionary() {
497 if (getPropertiesStorage())
498 return attrs;
499 return DictionaryAttr::get(getContext(),
500 llvm::to_vector(getDiscardableAttrs()));
501 }
502
503 /// Return all attributes that are not stored as properties.
504 DictionaryAttr getRawDictionaryAttrs() { return attrs; }
505
506 /// Return all of the attributes on this operation.
507 ArrayRef<NamedAttribute> getAttrs() { return getAttrDictionary().getValue(); }
508
509 /// Return all of the attributes on this operation as a DictionaryAttr.
510 DictionaryAttr getAttrDictionary();
511
512 /// Set the attributes from a dictionary on this operation.
513 /// These methods are expensive: if the dictionnary only contains discardable
514 /// attributes, `setDiscardableAttrs` is more efficient.
515 void setAttrs(DictionaryAttr newAttrs);
516 void setAttrs(ArrayRef<NamedAttribute> newAttrs);
517 /// Set the discardable attribute dictionary on this operation.
518 void setDiscardableAttrs(DictionaryAttr newAttrs) {
519 assert(newAttrs && "expected valid attribute dictionary");
520 attrs = newAttrs;
521 }
522 void setDiscardableAttrs(ArrayRef<NamedAttribute> newAttrs) {
523 setDiscardableAttrs(DictionaryAttr::get(getContext(), newAttrs));
524 }
525
526 /// Return the specified attribute if present, null otherwise.
527 /// These methods are expensive: if the dictionnary only contains discardable
528 /// attributes, `getDiscardableAttr` is more efficient.
529 Attribute getAttr(StringAttr name) {
530 if (getPropertiesStorageSize()) {
531 if (std::optional<Attribute> inherentAttr = getInherentAttr(name: name))
532 return *inherentAttr;
533 }
534 return attrs.get(name);
535 }
536 Attribute getAttr(StringRef name) {
537 if (getPropertiesStorageSize()) {
538 if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
539 return *inherentAttr;
540 }
541 return attrs.get(name);
542 }
543
544 template <typename AttrClass>
545 AttrClass getAttrOfType(StringAttr name) {
546 return llvm::dyn_cast_or_null<AttrClass>(getAttr(name));
547 }
548 template <typename AttrClass>
549 AttrClass getAttrOfType(StringRef name) {
550 return llvm::dyn_cast_or_null<AttrClass>(getAttr(name));
551 }
552
553 /// Return true if the operation has an attribute with the provided name,
554 /// false otherwise.
555 bool hasAttr(StringAttr name) {
556 if (getPropertiesStorageSize()) {
557 if (std::optional<Attribute> inherentAttr = getInherentAttr(name: name))
558 return (bool)*inherentAttr;
559 }
560 return attrs.contains(name);
561 }
562 bool hasAttr(StringRef name) {
563 if (getPropertiesStorageSize()) {
564 if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
565 return (bool)*inherentAttr;
566 }
567 return attrs.contains(name);
568 }
569 template <typename AttrClass, typename NameT>
570 bool hasAttrOfType(NameT &&name) {
571 return static_cast<bool>(
572 getAttrOfType<AttrClass>(std::forward<NameT>(name)));
573 }
574
575 /// If the an attribute exists with the specified name, change it to the new
576 /// value. Otherwise, add a new attribute with the specified name/value.
577 void setAttr(StringAttr name, Attribute value) {
578 if (getPropertiesStorageSize()) {
579 if (getInherentAttr(name: name)) {
580 setInherentAttr(name: name, value);
581 return;
582 }
583 }
584 NamedAttrList attributes(attrs);
585 if (attributes.set(name, value) != value)
586 attrs = attributes.getDictionary(getContext());
587 }
588 void setAttr(StringRef name, Attribute value) {
589 setAttr(StringAttr::get(getContext(), name), value);
590 }
591
592 /// Remove the attribute with the specified name if it exists. Return the
593 /// attribute that was erased, or nullptr if there was no attribute with such
594 /// name.
595 Attribute removeAttr(StringAttr name) {
596 if (getPropertiesStorageSize()) {
597 if (std::optional<Attribute> inherentAttr = getInherentAttr(name: name)) {
598 setInherentAttr(name: name, value: {});
599 return *inherentAttr;
600 }
601 }
602 NamedAttrList attributes(attrs);
603 Attribute removedAttr = attributes.erase(name);
604 if (removedAttr)
605 attrs = attributes.getDictionary(getContext());
606 return removedAttr;
607 }
608 Attribute removeAttr(StringRef name) {
609 return removeAttr(StringAttr::get(getContext(), name));
610 }
611
612 /// A utility iterator that filters out non-dialect attributes.
613 class dialect_attr_iterator
614 : public llvm::filter_iterator<ArrayRef<NamedAttribute>::iterator,
615 bool (*)(NamedAttribute)> {
616 static bool filter(NamedAttribute attr) {
617 // Dialect attributes are prefixed by the dialect name, like operations.
618 return attr.getName().strref().count('.');
619 }
620
621 explicit dialect_attr_iterator(ArrayRef<NamedAttribute>::iterator it,
622 ArrayRef<NamedAttribute>::iterator end)
623 : llvm::filter_iterator<ArrayRef<NamedAttribute>::iterator,
624 bool (*)(NamedAttribute)>(it, end, &filter) {}
625
626 // Allow access to the constructor.
627 friend Operation;
628 };
629 using dialect_attr_range = iterator_range<dialect_attr_iterator>;
630
631 /// Return a range corresponding to the dialect attributes for this operation.
632 dialect_attr_range getDialectAttrs() {
633 auto attrs = getAttrs();
634 return {dialect_attr_iterator(attrs.begin(), attrs.end()),
635 dialect_attr_iterator(attrs.end(), attrs.end())};
636 }
637 dialect_attr_iterator dialect_attr_begin() {
638 auto attrs = getAttrs();
639 return dialect_attr_iterator(attrs.begin(), attrs.end());
640 }
641 dialect_attr_iterator dialect_attr_end() {
642 auto attrs = getAttrs();
643 return dialect_attr_iterator(attrs.end(), attrs.end());
644 }
645
646 /// Set the dialect attributes for this operation, and preserve all inherent.
647 template <typename DialectAttrT>
648 void setDialectAttrs(DialectAttrT &&dialectAttrs) {
649 NamedAttrList attrs;
650 attrs.append(std::begin(dialectAttrs), std::end(dialectAttrs));
651 for (auto attr : getAttrs())
652 if (!attr.getName().strref().contains('.'))
653 attrs.push_back(newAttribute: attr);
654 setAttrs(attrs.getDictionary(getContext()));
655 }
656
657 /// Sets default attributes on unset attributes.
658 void populateDefaultAttrs() {
659 NamedAttrList attrs(getAttrDictionary());
660 name.populateDefaultAttrs(attrs);
661 setAttrs(attrs.getDictionary(getContext()));
662 }
663
664 //===--------------------------------------------------------------------===//
665 // Blocks
666 //===--------------------------------------------------------------------===//
667
668 /// Returns the number of regions held by this operation.
669 unsigned getNumRegions() { return numRegions; }
670
671 /// Returns the regions held by this operation.
672 MutableArrayRef<Region> getRegions() {
673 // Check the count first, as computing the trailing objects can be slow.
674 if (numRegions == 0)
675 return MutableArrayRef<Region>();
676
677 auto *regions = getTrailingObjects<Region>();
678 return {regions, numRegions};
679 }
680
681 /// Returns the region held by this operation at position 'index'.
682 Region &getRegion(unsigned index) {
683 assert(index < numRegions && "invalid region index");
684 return getRegions()[index];
685 }
686
687 //===--------------------------------------------------------------------===//
688 // Successors
689 //===--------------------------------------------------------------------===//
690
691 MutableArrayRef<BlockOperand> getBlockOperands() {
692 return {getTrailingObjects<BlockOperand>(), numSuccs};
693 }
694
695 // Successor iteration.
696 using succ_iterator = SuccessorRange::iterator;
697 succ_iterator successor_begin() { return getSuccessors().begin(); }
698 succ_iterator successor_end() { return getSuccessors().end(); }
699 SuccessorRange getSuccessors() { return SuccessorRange(this); }
700
701 bool hasSuccessors() { return numSuccs != 0; }
702 unsigned getNumSuccessors() { return numSuccs; }
703
704 Block *getSuccessor(unsigned index) {
705 assert(index < getNumSuccessors());
706 return getBlockOperands()[index].get();
707 }
708 void setSuccessor(Block *block, unsigned index);
709
710 //===--------------------------------------------------------------------===//
711 // Accessors for various properties of operations
712 //===--------------------------------------------------------------------===//
713
714 /// Attempt to fold this operation with the specified constant operand values
715 /// - the elements in "operands" will correspond directly to the operands of
716 /// the operation, but may be null if non-constant.
717 ///
718 /// If folding was successful, this function returns "success".
719 /// * If this operation was modified in-place (but not folded away),
720 /// `results` is empty.
721 /// * Otherwise, `results` is filled with the folded results.
722 /// If folding was unsuccessful, this function returns "failure".
723 LogicalResult fold(ArrayRef<Attribute> operands,
724 SmallVectorImpl<OpFoldResult> &results);
725
726 /// Attempt to fold this operation.
727 ///
728 /// If folding was successful, this function returns "success".
729 /// * If this operation was modified in-place (but not folded away),
730 /// `results` is empty.
731 /// * Otherwise, `results` is filled with the folded results.
732 /// If folding was unsuccessful, this function returns "failure".
733 LogicalResult fold(SmallVectorImpl<OpFoldResult> &results);
734
735 /// Returns true if `InterfaceT` has been promised by the dialect or
736 /// implemented.
737 template <typename InterfaceT>
738 bool hasPromiseOrImplementsInterface() const {
739 return name.hasPromiseOrImplementsInterface<InterfaceT>();
740 }
741
742 /// Returns true if the operation was registered with a particular trait, e.g.
743 /// hasTrait<OperandsAreSignlessIntegerLike>().
744 template <template <typename T> class Trait>
745 bool hasTrait() {
746 return name.hasTrait<Trait>();
747 }
748
749 /// Returns true if the operation *might* have the provided trait. This
750 /// means that either the operation is unregistered, or it was registered with
751 /// the provide trait.
752 template <template <typename T> class Trait>
753 bool mightHaveTrait() {
754 return name.mightHaveTrait<Trait>();
755 }
756
757 //===--------------------------------------------------------------------===//
758 // Operation Walkers
759 //===--------------------------------------------------------------------===//
760
761 /// Walk the operation by calling the callback for each nested operation
762 /// (including this one), block or region, depending on the callback provided.
763 /// The order in which regions, blocks and operations at the same nesting
764 /// level are visited (e.g., lexicographical or reverse lexicographical order)
765 /// is determined by 'Iterator'. The walk order for enclosing regions, blocks
766 /// and operations with respect to their nested ones is specified by 'Order'
767 /// (post-order by default). A callback on a block or operation is allowed to
768 /// erase that block or operation if either:
769 /// * the walk is in post-order, or
770 /// * the walk is in pre-order and the walk is skipped after the erasure.
771 ///
772 /// The callback method can take any of the following forms:
773 /// void(Operation*) : Walk all operations opaquely.
774 /// * op->walk([](Operation *nestedOp) { ...});
775 /// void(OpT) : Walk all operations of the given derived type.
776 /// * op->walk([](ReturnOp returnOp) { ...});
777 /// WalkResult(Operation*|OpT) : Walk operations, but allow for
778 /// interruption/skipping.
779 /// * op->walk([](... op) {
780 /// // Skip the walk of this op based on some invariant.
781 /// if (some_invariant)
782 /// return WalkResult::skip();
783 /// // Interrupt, i.e cancel, the walk based on some invariant.
784 /// if (another_invariant)
785 /// return WalkResult::interrupt();
786 /// return WalkResult::advance();
787 /// });
788 template <WalkOrder Order = WalkOrder::PostOrder,
789 typename Iterator = ForwardIterator, typename FnT,
790 typename RetT = detail::walkResultType<FnT>>
791 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 1,
792 RetT>
793 walk(FnT &&callback) {
794 return detail::walk<Order, Iterator>(this, std::forward<FnT>(callback));
795 }
796
797 /// Generic walker with a stage aware callback. Walk the operation by calling
798 /// the callback for each nested operation (including this one) N+1 times,
799 /// where N is the number of regions attached to that operation.
800 ///
801 /// The callback method can take any of the following forms:
802 /// void(Operation *, const WalkStage &) : Walk all operation opaquely
803 /// * op->walk([](Operation *nestedOp, const WalkStage &stage) { ...});
804 /// void(OpT, const WalkStage &) : Walk all operations of the given derived
805 /// type.
806 /// * op->walk([](ReturnOp returnOp, const WalkStage &stage) { ...});
807 /// WalkResult(Operation*|OpT, const WalkStage &stage) : Walk operations,
808 /// but allow for interruption/skipping.
809 /// * op->walk([](... op, const WalkStage &stage) {
810 /// // Skip the walk of this op based on some invariant.
811 /// if (some_invariant)
812 /// return WalkResult::skip();
813 /// // Interrupt, i.e cancel, the walk based on some invariant.
814 /// if (another_invariant)
815 /// return WalkResult::interrupt();
816 /// return WalkResult::advance();
817 /// });
818 template <typename FnT, typename RetT = detail::walkResultType<FnT>>
819 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 2,
820 RetT>
821 walk(FnT &&callback) {
822 return detail::walk(this, std::forward<FnT>(callback));
823 }
824
825 //===--------------------------------------------------------------------===//
826 // Uses
827 //===--------------------------------------------------------------------===//
828
829 /// Drop all uses of results of this operation.
830 void dropAllUses() {
831 for (OpResult result : getOpResults())
832 result.dropAllUses();
833 }
834
835 using use_iterator = result_range::use_iterator;
836 using use_range = result_range::use_range;
837
838 use_iterator use_begin() { return getResults().use_begin(); }
839 use_iterator use_end() { return getResults().use_end(); }
840
841 /// Returns a range of all uses, which is useful for iterating over all uses.
842 use_range getUses() { return getResults().getUses(); }
843
844 /// Returns true if this operation has exactly one use.
845 bool hasOneUse() { return llvm::hasSingleElement(C: getUses()); }
846
847 /// Returns true if this operation has no uses.
848 bool use_empty() { return getResults().use_empty(); }
849
850 /// Returns true if the results of this operation are used outside of the
851 /// given block.
852 bool isUsedOutsideOfBlock(Block *block) {
853 return llvm::any_of(Range: getOpResults(), P: [block](OpResult result) {
854 return result.isUsedOutsideOfBlock(block);
855 });
856 }
857
858 //===--------------------------------------------------------------------===//
859 // Users
860 //===--------------------------------------------------------------------===//
861
862 using user_iterator = ValueUserIterator<use_iterator, OpOperand>;
863 using user_range = iterator_range<user_iterator>;
864
865 user_iterator user_begin() { return user_iterator(use_begin()); }
866 user_iterator user_end() { return user_iterator(use_end()); }
867
868 /// Returns a range of all users.
869 user_range getUsers() { return {user_begin(), user_end()}; }
870
871 //===--------------------------------------------------------------------===//
872 // Other
873 //===--------------------------------------------------------------------===//
874
875 /// Emit an error with the op name prefixed, like "'dim' op " which is
876 /// convenient for verifiers.
877 InFlightDiagnostic emitOpError(const Twine &message = {});
878
879 /// Emit an error about fatal conditions with this operation, reporting up to
880 /// any diagnostic handlers that may be listening.
881 InFlightDiagnostic emitError(const Twine &message = {});
882
883 /// Emit a warning about this operation, reporting up to any diagnostic
884 /// handlers that may be listening.
885 InFlightDiagnostic emitWarning(const Twine &message = {});
886
887 /// Emit a remark about this operation, reporting up to any diagnostic
888 /// handlers that may be listening.
889 InFlightDiagnostic emitRemark(const Twine &message = {});
890
891 /// Returns the properties storage size.
892 int getPropertiesStorageSize() const {
893 return ((int)propertiesStorageSize) * 8;
894 }
895 /// Returns the properties storage.
896 OpaqueProperties getPropertiesStorage() {
897 if (propertiesStorageSize)
898 return getPropertiesStorageUnsafe();
899 return {nullptr};
900 }
901 OpaqueProperties getPropertiesStorage() const {
902 if (propertiesStorageSize)
903 return {reinterpret_cast<void *>(const_cast<detail::OpProperties *>(
904 getTrailingObjects<detail::OpProperties>()))};
905 return {nullptr};
906 }
907 /// Returns the properties storage without checking whether properties are
908 /// present.
909 OpaqueProperties getPropertiesStorageUnsafe() {
910 return {
911 reinterpret_cast<void *>(getTrailingObjects<detail::OpProperties>())};
912 }
913
914 /// Return the properties converted to an attribute.
915 /// This is expensive, and mostly useful when dealing with unregistered
916 /// operation. Returns an empty attribute if no properties are present.
917 Attribute getPropertiesAsAttribute();
918
919 /// Set the properties from the provided attribute.
920 /// This is an expensive operation that can fail if the attribute is not
921 /// matching the expectations of the properties for this operation. This is
922 /// mostly useful for unregistered operations or used when parsing the
923 /// generic format. An optional diagnostic can be passed in for richer errors.
924 LogicalResult
925 setPropertiesFromAttribute(Attribute attr,
926 function_ref<InFlightDiagnostic()> emitError);
927
928 /// Copy properties from an existing other properties object. The two objects
929 /// must be the same type.
930 void copyProperties(OpaqueProperties rhs);
931
932 /// Compute a hash for the op properties (if any).
933 llvm::hash_code hashProperties();
934
935private:
936 //===--------------------------------------------------------------------===//
937 // Ordering
938 //===--------------------------------------------------------------------===//
939
940 /// This value represents an invalid index ordering for an operation within a
941 /// block.
942 static constexpr unsigned kInvalidOrderIdx = -1;
943
944 /// This value represents the stride to use when computing a new order for an
945 /// operation.
946 static constexpr unsigned kOrderStride = 5;
947
948 /// Update the order index of this operation of this operation if necessary,
949 /// potentially recomputing the order of the parent block.
950 void updateOrderIfNecessary();
951
952 /// Returns true if this operation has a valid order.
953 bool hasValidOrder() { return orderIndex != kInvalidOrderIdx; }
954
955private:
956 Operation(Location location, OperationName name, unsigned numResults,
957 unsigned numSuccessors, unsigned numRegions,
958 int propertiesStorageSize, DictionaryAttr attributes,
959 OpaqueProperties properties, bool hasOperandStorage);
960
961 // Operations are deleted through the destroy() member because they are
962 // allocated with malloc.
963 ~Operation();
964
965 /// Returns the additional size necessary for allocating the given objects
966 /// before an Operation in-memory.
967 static size_t prefixAllocSize(unsigned numOutOfLineResults,
968 unsigned numInlineResults) {
969 return sizeof(detail::OutOfLineOpResult) * numOutOfLineResults +
970 sizeof(detail::InlineOpResult) * numInlineResults;
971 }
972 /// Returns the additional size allocated before this Operation in-memory.
973 size_t prefixAllocSize() {
974 unsigned numResults = getNumResults();
975 unsigned numOutOfLineResults = OpResult::getNumTrailing(numResults);
976 unsigned numInlineResults = OpResult::getNumInline(numResults);
977 return prefixAllocSize(numOutOfLineResults, numInlineResults);
978 }
979
980 /// Returns the operand storage object.
981 detail::OperandStorage &getOperandStorage() {
982 assert(hasOperandStorage && "expected operation to have operand storage");
983 return *getTrailingObjects<detail::OperandStorage>();
984 }
985
986 /// Returns a pointer to the use list for the given out-of-line result.
987 detail::OutOfLineOpResult *getOutOfLineOpResult(unsigned resultNumber) {
988 // Out-of-line results are stored in reverse order after (before in memory)
989 // the inline results.
990 return reinterpret_cast<detail::OutOfLineOpResult *>(getInlineOpResult(
991 resultNumber: detail::OpResultImpl::getMaxInlineResults() - 1)) -
992 ++resultNumber;
993 }
994
995 /// Returns a pointer to the use list for the given inline result.
996 detail::InlineOpResult *getInlineOpResult(unsigned resultNumber) {
997 // Inline results are stored in reverse order before the operation in
998 // memory.
999 return reinterpret_cast<detail::InlineOpResult *>(this) - ++resultNumber;
1000 }
1001
1002 /// Returns a pointer to the use list for the given result, which may be
1003 /// either inline or out-of-line.
1004 detail::OpResultImpl *getOpResultImpl(unsigned resultNumber) {
1005 assert(resultNumber < getNumResults() &&
1006 "Result number is out of range for operation");
1007 unsigned maxInlineResults = detail::OpResultImpl::getMaxInlineResults();
1008 if (resultNumber < maxInlineResults)
1009 return getInlineOpResult(resultNumber);
1010 return getOutOfLineOpResult(resultNumber: resultNumber - maxInlineResults);
1011 }
1012
1013 /// Provide a 'getParent' method for ilist_node_with_parent methods.
1014 /// We mark it as a const function because ilist_node_with_parent specifically
1015 /// requires a 'getParent() const' method. Once ilist_node removes this
1016 /// constraint, we should drop the const to fit the rest of the MLIR const
1017 /// model.
1018 Block *getParent() const { return block; }
1019
1020 /// Expose a few methods explicitly for the debugger to call for
1021 /// visualization.
1022#ifndef NDEBUG
1023 LLVM_DUMP_METHOD operand_range debug_getOperands() { return getOperands(); }
1024 LLVM_DUMP_METHOD result_range debug_getResults() { return getResults(); }
1025 LLVM_DUMP_METHOD SuccessorRange debug_getSuccessors() {
1026 return getSuccessors();
1027 }
1028 LLVM_DUMP_METHOD MutableArrayRef<Region> debug_getRegions() {
1029 return getRegions();
1030 }
1031#endif
1032
1033 /// The operation block that contains this operation.
1034 Block *block = nullptr;
1035
1036 /// This holds information about the source location the operation was defined
1037 /// or derived from.
1038 Location location;
1039
1040 /// Relative order of this operation in its parent block. Used for
1041 /// O(1) local dominance checks between operations.
1042 mutable unsigned orderIndex = 0;
1043
1044 const unsigned numResults;
1045 const unsigned numSuccs;
1046 const unsigned numRegions : 23;
1047
1048 /// This bit signals whether this operation has an operand storage or not. The
1049 /// operand storage may be elided for operations that are known to never have
1050 /// operands.
1051 bool hasOperandStorage : 1;
1052
1053 /// The size of the storage for properties (if any), divided by 8: since the
1054 /// Properties storage will always be rounded up to the next multiple of 8 we
1055 /// save some bits here.
1056 unsigned char propertiesStorageSize : 8;
1057 /// This is the maximum size we support to allocate properties inline with an
1058 /// operation: this must match the bitwidth above.
1059 static constexpr int64_t propertiesCapacity = 8 * 256;
1060
1061 /// This holds the name of the operation.
1062 OperationName name;
1063
1064 /// This holds general named attributes for the operation.
1065 DictionaryAttr attrs;
1066
1067 // allow ilist_traits access to 'block' field.
1068 friend struct llvm::ilist_traits<Operation>;
1069
1070 // allow block to access the 'orderIndex' field.
1071 friend class Block;
1072
1073 // allow value to access the 'ResultStorage' methods.
1074 friend class Value;
1075
1076 // allow ilist_node_with_parent to access the 'getParent' method.
1077 friend class llvm::ilist_node_with_parent<Operation, Block>;
1078
1079 // This stuff is used by the TrailingObjects template.
1080 friend llvm::TrailingObjects<Operation, detail::OperandStorage,
1081 detail::OpProperties, BlockOperand, Region,
1082 OpOperand>;
1083 size_t numTrailingObjects(OverloadToken<detail::OperandStorage>) const {
1084 return hasOperandStorage ? 1 : 0;
1085 }
1086 size_t numTrailingObjects(OverloadToken<BlockOperand>) const {
1087 return numSuccs;
1088 }
1089 size_t numTrailingObjects(OverloadToken<Region>) const { return numRegions; }
1090 size_t numTrailingObjects(OverloadToken<detail::OpProperties>) const {
1091 return getPropertiesStorageSize();
1092 }
1093};
1094
1095inline raw_ostream &operator<<(raw_ostream &os, const Operation &op) {
1096 const_cast<Operation &>(op).print(os, flags: OpPrintingFlags().useLocalScope());
1097 return os;
1098}
1099
1100} // namespace mlir
1101
1102namespace llvm {
1103/// Cast from an (const) Operation * to a derived operation type.
1104template <typename T>
1105struct CastInfo<T, ::mlir::Operation *>
1106 : public ValueFromPointerCast<T, ::mlir::Operation,
1107 CastInfo<T, ::mlir::Operation *>> {
1108 static bool isPossible(::mlir::Operation *op) { return T::classof(op); }
1109};
1110template <typename T>
1111struct CastInfo<T, const ::mlir::Operation *>
1112 : public ConstStrippingForwardingCast<T, const ::mlir::Operation *,
1113 CastInfo<T, ::mlir::Operation *>> {};
1114
1115/// Cast from an (const) Operation & to a derived operation type.
1116template <typename T>
1117struct CastInfo<T, ::mlir::Operation>
1118 : public NullableValueCastFailed<T>,
1119 public DefaultDoCastIfPossible<T, ::mlir::Operation &,
1120 CastInfo<T, ::mlir::Operation>> {
1121 // Provide isPossible here because here we have the const-stripping from
1122 // ConstStrippingCast.
1123 static bool isPossible(::mlir::Operation &val) { return T::classof(&val); }
1124 static T doCast(::mlir::Operation &val) { return T(&val); }
1125};
1126template <typename T>
1127struct CastInfo<T, const ::mlir::Operation>
1128 : public ConstStrippingForwardingCast<T, const ::mlir::Operation,
1129 CastInfo<T, ::mlir::Operation>> {};
1130
1131/// Cast (const) Operation * to itself. This is helpful to avoid SFINAE in
1132/// templated implementations that should work on both base and derived
1133/// operation types.
1134template <>
1135struct CastInfo<::mlir::Operation *, ::mlir::Operation *>
1136 : public NullableValueCastFailed<::mlir::Operation *>,
1137 public DefaultDoCastIfPossible<
1138 ::mlir::Operation *, ::mlir::Operation *,
1139 CastInfo<::mlir::Operation *, ::mlir::Operation *>> {
1140 static bool isPossible(::mlir::Operation *op) { return true; }
1141 static ::mlir::Operation *doCast(::mlir::Operation *op) { return op; }
1142};
1143template <>
1144struct CastInfo<const ::mlir::Operation *, const ::mlir::Operation *>
1145 : public ConstStrippingForwardingCast<
1146 const ::mlir::Operation *, const ::mlir::Operation *,
1147 CastInfo<::mlir::Operation *, ::mlir::Operation *>> {};
1148} // namespace llvm
1149
1150#endif // MLIR_IR_OPERATION_H
1151

source code of mlir/include/mlir/IR/Operation.h