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 // Dump pretty printed IR. This method is helpful for better readability if
326 // the Operation is not verified because it won't disable custom printers to
327 // fall back to the generic one.
328 LLVM_DUMP_METHOD void dumpPretty();
329
330 //===--------------------------------------------------------------------===//
331 // Operands
332 //===--------------------------------------------------------------------===//
333
334 /// Replace the current operands of this operation with the ones provided in
335 /// 'operands'.
336 void setOperands(ValueRange operands);
337
338 /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
339 /// with the ones provided in 'operands'. 'operands' may be smaller or larger
340 /// than the range pointed to by 'start'+'length'.
341 void setOperands(unsigned start, unsigned length, ValueRange operands);
342
343 /// Insert the given operands into the operand list at the given 'index'.
344 void insertOperands(unsigned index, ValueRange operands);
345
346 unsigned getNumOperands() {
347 return LLVM_LIKELY(hasOperandStorage) ? getOperandStorage().size() : 0;
348 }
349
350 Value getOperand(unsigned idx) { return getOpOperand(idx).get(); }
351 void setOperand(unsigned idx, Value value) {
352 return getOpOperand(idx).set(value);
353 }
354
355 /// Erase the operand at position `idx`.
356 void eraseOperand(unsigned idx) { eraseOperands(idx); }
357
358 /// Erase the operands starting at position `idx` and ending at position
359 /// 'idx'+'length'.
360 void eraseOperands(unsigned idx, unsigned length = 1) {
361 getOperandStorage().eraseOperands(start: idx, length);
362 }
363
364 /// Erases the operands that have their corresponding bit set in
365 /// `eraseIndices` and removes them from the operand list.
366 void eraseOperands(const BitVector &eraseIndices) {
367 getOperandStorage().eraseOperands(eraseIndices);
368 }
369
370 // Support operand iteration.
371 using operand_range = OperandRange;
372 using operand_iterator = operand_range::iterator;
373
374 operand_iterator operand_begin() { return getOperands().begin(); }
375 operand_iterator operand_end() { return getOperands().end(); }
376
377 /// Returns an iterator on the underlying Value's.
378 operand_range getOperands() {
379 MutableArrayRef<OpOperand> operands = getOpOperands();
380 return OperandRange(operands.data(), operands.size());
381 }
382
383 MutableArrayRef<OpOperand> getOpOperands() {
384 return LLVM_LIKELY(hasOperandStorage) ? getOperandStorage().getOperands()
385 : MutableArrayRef<OpOperand>();
386 }
387
388 OpOperand &getOpOperand(unsigned idx) {
389 return getOperandStorage().getOperands()[idx];
390 }
391
392 // Support operand type iteration.
393 using operand_type_iterator = operand_range::type_iterator;
394 using operand_type_range = operand_range::type_range;
395 operand_type_iterator operand_type_begin() { return operand_begin(); }
396 operand_type_iterator operand_type_end() { return operand_end(); }
397 operand_type_range getOperandTypes() { return getOperands().getTypes(); }
398
399 //===--------------------------------------------------------------------===//
400 // Results
401 //===--------------------------------------------------------------------===//
402
403 /// Return the number of results held by this operation.
404 unsigned getNumResults() { return numResults; }
405
406 /// Get the 'idx'th result of this operation.
407 OpResult getResult(unsigned idx) { return OpResult(getOpResultImpl(resultNumber: idx)); }
408
409 /// Support result iteration.
410 using result_range = ResultRange;
411 using result_iterator = result_range::iterator;
412
413 result_iterator result_begin() { return getResults().begin(); }
414 result_iterator result_end() { return getResults().end(); }
415 result_range getResults() {
416 return numResults == 0 ? result_range(nullptr, 0)
417 : result_range(getInlineOpResult(resultNumber: 0), numResults);
418 }
419
420 result_range getOpResults() { return getResults(); }
421 OpResult getOpResult(unsigned idx) { return getResult(idx); }
422
423 /// Support result type iteration.
424 using result_type_iterator = result_range::type_iterator;
425 using result_type_range = result_range::type_range;
426 result_type_iterator result_type_begin() { return getResultTypes().begin(); }
427 result_type_iterator result_type_end() { return getResultTypes().end(); }
428 result_type_range getResultTypes() { return getResults().getTypes(); }
429
430 //===--------------------------------------------------------------------===//
431 // Attributes
432 //===--------------------------------------------------------------------===//
433
434 // Operations may optionally carry a list of attributes that associate
435 // constants to names. Attributes may be dynamically added and removed over
436 // the lifetime of an operation.
437
438 /// Access an inherent attribute by name: returns an empty optional if there
439 /// is no inherent attribute with this name.
440 ///
441 /// This method is available as a transient facility in the migration process
442 /// to use Properties instead.
443 std::optional<Attribute> getInherentAttr(StringRef name);
444
445 /// Set an inherent attribute by name.
446 ///
447 /// This method is available as a transient facility in the migration process
448 /// to use Properties instead.
449 void setInherentAttr(StringAttr name, Attribute value);
450
451 /// Access a discardable attribute by name, returns an null Attribute if the
452 /// discardable attribute does not exist.
453 Attribute getDiscardableAttr(StringRef name) { return attrs.get(name); }
454
455 /// Access a discardable attribute by name, returns an null Attribute if the
456 /// discardable attribute does not exist.
457 Attribute getDiscardableAttr(StringAttr name) { return attrs.get(name); }
458
459 /// Set a discardable attribute by name.
460 void setDiscardableAttr(StringAttr name, Attribute value) {
461 NamedAttrList attributes(attrs);
462 if (attributes.set(name, value) != value)
463 attrs = attributes.getDictionary(getContext());
464 }
465 void setDiscardableAttr(StringRef name, Attribute value) {
466 setDiscardableAttr(StringAttr::get(getContext(), name), value);
467 }
468
469 /// Remove the discardable attribute with the specified name if it exists.
470 /// Return the attribute that was erased, or nullptr if there was no attribute
471 /// with such name.
472 Attribute removeDiscardableAttr(StringAttr name) {
473 NamedAttrList attributes(attrs);
474 Attribute removedAttr = attributes.erase(name);
475 if (removedAttr)
476 attrs = attributes.getDictionary(getContext());
477 return removedAttr;
478 }
479 Attribute removeDiscardableAttr(StringRef name) {
480 return removeDiscardableAttr(StringAttr::get(getContext(), name));
481 }
482
483 /// Return a range of all of discardable attributes on this operation. Note
484 /// that for unregistered operations that are not storing inherent attributes
485 /// as properties, all attributes are considered discardable.
486 auto getDiscardableAttrs() {
487 std::optional<RegisteredOperationName> opName = getRegisteredInfo();
488 ArrayRef<StringAttr> attributeNames =
489 opName ? getRegisteredInfo()->getAttributeNames()
490 : ArrayRef<StringAttr>();
491 return llvm::make_filter_range(
492 attrs.getValue(),
493 [this, attributeNames](const NamedAttribute attribute) {
494 return getPropertiesStorage() ||
495 !llvm::is_contained(attributeNames, attribute.getName());
496 });
497 }
498
499 /// Return all of the discardable attributes on this operation as a
500 /// DictionaryAttr.
501 DictionaryAttr getDiscardableAttrDictionary() {
502 if (getPropertiesStorage())
503 return attrs;
504 return DictionaryAttr::get(getContext(),
505 llvm::to_vector(getDiscardableAttrs()));
506 }
507
508 /// Return all attributes that are not stored as properties.
509 DictionaryAttr getRawDictionaryAttrs() { return attrs; }
510
511 /// Return all of the attributes on this operation.
512 ArrayRef<NamedAttribute> getAttrs() { return getAttrDictionary().getValue(); }
513
514 /// Return all of the attributes on this operation as a DictionaryAttr.
515 DictionaryAttr getAttrDictionary();
516
517 /// Set the attributes from a dictionary on this operation.
518 /// These methods are expensive: if the dictionnary only contains discardable
519 /// attributes, `setDiscardableAttrs` is more efficient.
520 void setAttrs(DictionaryAttr newAttrs);
521 void setAttrs(ArrayRef<NamedAttribute> newAttrs);
522 /// Set the discardable attribute dictionary on this operation.
523 void setDiscardableAttrs(DictionaryAttr newAttrs) {
524 assert(newAttrs && "expected valid attribute dictionary");
525 attrs = newAttrs;
526 }
527 void setDiscardableAttrs(ArrayRef<NamedAttribute> newAttrs) {
528 setDiscardableAttrs(DictionaryAttr::get(getContext(), newAttrs));
529 }
530
531 /// Return the specified attribute if present, null otherwise.
532 /// These methods are expensive: if the dictionnary only contains discardable
533 /// attributes, `getDiscardableAttr` is more efficient.
534 Attribute getAttr(StringAttr name) {
535 if (getPropertiesStorageSize()) {
536 if (std::optional<Attribute> inherentAttr = getInherentAttr(name: name))
537 return *inherentAttr;
538 }
539 return attrs.get(name);
540 }
541 Attribute getAttr(StringRef name) {
542 if (getPropertiesStorageSize()) {
543 if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
544 return *inherentAttr;
545 }
546 return attrs.get(name);
547 }
548
549 template <typename AttrClass>
550 AttrClass getAttrOfType(StringAttr name) {
551 return llvm::dyn_cast_or_null<AttrClass>(getAttr(name));
552 }
553 template <typename AttrClass>
554 AttrClass getAttrOfType(StringRef name) {
555 return llvm::dyn_cast_or_null<AttrClass>(getAttr(name));
556 }
557
558 /// Return true if the operation has an attribute with the provided name,
559 /// false otherwise.
560 bool hasAttr(StringAttr name) {
561 if (getPropertiesStorageSize()) {
562 if (std::optional<Attribute> inherentAttr = getInherentAttr(name: name))
563 return (bool)*inherentAttr;
564 }
565 return attrs.contains(name);
566 }
567 bool hasAttr(StringRef name) {
568 if (getPropertiesStorageSize()) {
569 if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
570 return (bool)*inherentAttr;
571 }
572 return attrs.contains(name);
573 }
574 template <typename AttrClass, typename NameT>
575 bool hasAttrOfType(NameT &&name) {
576 return static_cast<bool>(
577 getAttrOfType<AttrClass>(std::forward<NameT>(name)));
578 }
579
580 /// If the an attribute exists with the specified name, change it to the new
581 /// value. Otherwise, add a new attribute with the specified name/value.
582 void setAttr(StringAttr name, Attribute value) {
583 if (getPropertiesStorageSize()) {
584 if (getInherentAttr(name: name)) {
585 setInherentAttr(name: name, value);
586 return;
587 }
588 }
589 NamedAttrList attributes(attrs);
590 if (attributes.set(name, value) != value)
591 attrs = attributes.getDictionary(getContext());
592 }
593 void setAttr(StringRef name, Attribute value) {
594 setAttr(StringAttr::get(getContext(), name), value);
595 }
596
597 /// Remove the attribute with the specified name if it exists. Return the
598 /// attribute that was erased, or nullptr if there was no attribute with such
599 /// name.
600 Attribute removeAttr(StringAttr name) {
601 if (getPropertiesStorageSize()) {
602 if (std::optional<Attribute> inherentAttr = getInherentAttr(name: name)) {
603 setInherentAttr(name: name, value: {});
604 return *inherentAttr;
605 }
606 }
607 NamedAttrList attributes(attrs);
608 Attribute removedAttr = attributes.erase(name);
609 if (removedAttr)
610 attrs = attributes.getDictionary(getContext());
611 return removedAttr;
612 }
613 Attribute removeAttr(StringRef name) {
614 return removeAttr(StringAttr::get(getContext(), name));
615 }
616
617 /// A utility iterator that filters out non-dialect attributes.
618 class dialect_attr_iterator
619 : public llvm::filter_iterator<ArrayRef<NamedAttribute>::iterator,
620 bool (*)(NamedAttribute)> {
621 static bool filter(NamedAttribute attr) {
622 // Dialect attributes are prefixed by the dialect name, like operations.
623 return attr.getName().strref().count('.');
624 }
625
626 explicit dialect_attr_iterator(ArrayRef<NamedAttribute>::iterator it,
627 ArrayRef<NamedAttribute>::iterator end)
628 : llvm::filter_iterator<ArrayRef<NamedAttribute>::iterator,
629 bool (*)(NamedAttribute)>(it, end, &filter) {}
630
631 // Allow access to the constructor.
632 friend Operation;
633 };
634 using dialect_attr_range = iterator_range<dialect_attr_iterator>;
635
636 /// Return a range corresponding to the dialect attributes for this operation.
637 dialect_attr_range getDialectAttrs() {
638 auto attrs = getAttrs();
639 return {dialect_attr_iterator(attrs.begin(), attrs.end()),
640 dialect_attr_iterator(attrs.end(), attrs.end())};
641 }
642 dialect_attr_iterator dialect_attr_begin() {
643 auto attrs = getAttrs();
644 return dialect_attr_iterator(attrs.begin(), attrs.end());
645 }
646 dialect_attr_iterator dialect_attr_end() {
647 auto attrs = getAttrs();
648 return dialect_attr_iterator(attrs.end(), attrs.end());
649 }
650
651 /// Set the dialect attributes for this operation, and preserve all inherent.
652 template <typename DialectAttrT>
653 void setDialectAttrs(DialectAttrT &&dialectAttrs) {
654 NamedAttrList attrs;
655 attrs.append(std::begin(dialectAttrs), std::end(dialectAttrs));
656 for (auto attr : getAttrs())
657 if (!attr.getName().strref().contains('.'))
658 attrs.push_back(newAttribute: attr);
659 setAttrs(attrs.getDictionary(getContext()));
660 }
661
662 /// Sets default attributes on unset attributes.
663 void populateDefaultAttrs() {
664 NamedAttrList attrs(getAttrDictionary());
665 name.populateDefaultAttrs(attrs);
666 setAttrs(attrs.getDictionary(getContext()));
667 }
668
669 //===--------------------------------------------------------------------===//
670 // Blocks
671 //===--------------------------------------------------------------------===//
672
673 /// Returns the number of regions held by this operation.
674 unsigned getNumRegions() { return numRegions; }
675
676 /// Returns the regions held by this operation.
677 MutableArrayRef<Region> getRegions() {
678 // Check the count first, as computing the trailing objects can be slow.
679 if (numRegions == 0)
680 return MutableArrayRef<Region>();
681
682 return getTrailingObjects<Region>(numRegions);
683 }
684
685 /// Returns the region held by this operation at position 'index'.
686 Region &getRegion(unsigned index) {
687 assert(index < numRegions && "invalid region index");
688 return getRegions()[index];
689 }
690
691 //===--------------------------------------------------------------------===//
692 // Successors
693 //===--------------------------------------------------------------------===//
694
695 MutableArrayRef<BlockOperand> getBlockOperands() {
696 return getTrailingObjects<BlockOperand>(numSuccs);
697 }
698
699 // Successor iteration.
700 using succ_iterator = SuccessorRange::iterator;
701 succ_iterator successor_begin() { return getSuccessors().begin(); }
702 succ_iterator successor_end() { return getSuccessors().end(); }
703 SuccessorRange getSuccessors() { return SuccessorRange(this); }
704
705 bool hasSuccessors() { return numSuccs != 0; }
706 unsigned getNumSuccessors() { return numSuccs; }
707
708 Block *getSuccessor(unsigned index) {
709 assert(index < getNumSuccessors());
710 return getBlockOperands()[index].get();
711 }
712 void setSuccessor(Block *block, unsigned index);
713
714 //===--------------------------------------------------------------------===//
715 // Accessors for various properties of operations
716 //===--------------------------------------------------------------------===//
717
718 /// Attempt to fold this operation with the specified constant operand values
719 /// - the elements in "operands" will correspond directly to the operands of
720 /// the operation, but may be null if non-constant.
721 ///
722 /// If folding was successful, this function returns "success".
723 /// * If this operation was modified in-place (but not folded away),
724 /// `results` is empty.
725 /// * Otherwise, `results` is filled with the folded results.
726 /// If folding was unsuccessful, this function returns "failure".
727 LogicalResult fold(ArrayRef<Attribute> operands,
728 SmallVectorImpl<OpFoldResult> &results);
729
730 /// Attempt to fold this operation.
731 ///
732 /// If folding was successful, this function returns "success".
733 /// * If this operation was modified in-place (but not folded away),
734 /// `results` is empty.
735 /// * Otherwise, `results` is filled with the folded results.
736 /// If folding was unsuccessful, this function returns "failure".
737 LogicalResult fold(SmallVectorImpl<OpFoldResult> &results);
738
739 /// Returns true if `InterfaceT` has been promised by the dialect or
740 /// implemented.
741 template <typename InterfaceT>
742 bool hasPromiseOrImplementsInterface() const {
743 return name.hasPromiseOrImplementsInterface<InterfaceT>();
744 }
745
746 /// Returns true if the operation was registered with a particular trait, e.g.
747 /// hasTrait<OperandsAreSignlessIntegerLike>().
748 template <template <typename T> class Trait>
749 bool hasTrait() {
750 return name.hasTrait<Trait>();
751 }
752
753 /// Returns true if the operation *might* have the provided trait. This
754 /// means that either the operation is unregistered, or it was registered with
755 /// the provide trait.
756 template <template <typename T> class Trait>
757 bool mightHaveTrait() {
758 return name.mightHaveTrait<Trait>();
759 }
760
761 //===--------------------------------------------------------------------===//
762 // Operation Walkers
763 //===--------------------------------------------------------------------===//
764
765 /// Walk the operation by calling the callback for each nested operation
766 /// (including this one), block or region, depending on the callback provided.
767 /// The order in which regions, blocks and operations at the same nesting
768 /// level are visited (e.g., lexicographical or reverse lexicographical order)
769 /// is determined by 'Iterator'. The walk order for enclosing regions, blocks
770 /// and operations with respect to their nested ones is specified by 'Order'
771 /// (post-order by default). A callback on a block or operation is allowed to
772 /// erase that block or operation if either:
773 /// * the walk is in post-order, or
774 /// * the walk is in pre-order and the walk is skipped after the erasure.
775 ///
776 /// The callback method can take any of the following forms:
777 /// void(Operation*) : Walk all operations opaquely.
778 /// * op->walk([](Operation *nestedOp) { ...});
779 /// void(OpT) : Walk all operations of the given derived type.
780 /// * op->walk([](ReturnOp returnOp) { ...});
781 /// WalkResult(Operation*|OpT) : Walk operations, but allow for
782 /// interruption/skipping.
783 /// * op->walk([](... op) {
784 /// // Skip the walk of this op based on some invariant.
785 /// if (some_invariant)
786 /// return WalkResult::skip();
787 /// // Interrupt, i.e cancel, the walk based on some invariant.
788 /// if (another_invariant)
789 /// return WalkResult::interrupt();
790 /// return WalkResult::advance();
791 /// });
792 template <WalkOrder Order = WalkOrder::PostOrder,
793 typename Iterator = ForwardIterator, typename FnT,
794 typename RetT = detail::walkResultType<FnT>>
795 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 1,
796 RetT>
797 walk(FnT &&callback) {
798 return detail::walk<Order, Iterator>(this, std::forward<FnT>(callback));
799 }
800
801 /// Generic walker with a stage aware callback. Walk the operation by calling
802 /// the callback for each nested operation (including this one) N+1 times,
803 /// where N is the number of regions attached to that operation.
804 ///
805 /// The callback method can take any of the following forms:
806 /// void(Operation *, const WalkStage &) : Walk all operation opaquely
807 /// * op->walk([](Operation *nestedOp, const WalkStage &stage) { ...});
808 /// void(OpT, const WalkStage &) : Walk all operations of the given derived
809 /// type.
810 /// * op->walk([](ReturnOp returnOp, const WalkStage &stage) { ...});
811 /// WalkResult(Operation*|OpT, const WalkStage &stage) : Walk operations,
812 /// but allow for interruption/skipping.
813 /// * op->walk([](... op, const WalkStage &stage) {
814 /// // Skip the walk of this op based on some invariant.
815 /// if (some_invariant)
816 /// return WalkResult::skip();
817 /// // Interrupt, i.e cancel, the walk based on some invariant.
818 /// if (another_invariant)
819 /// return WalkResult::interrupt();
820 /// return WalkResult::advance();
821 /// });
822 template <typename FnT, typename RetT = detail::walkResultType<FnT>>
823 std::enable_if_t<llvm::function_traits<std::decay_t<FnT>>::num_args == 2,
824 RetT>
825 walk(FnT &&callback) {
826 return detail::walk(this, std::forward<FnT>(callback));
827 }
828
829 //===--------------------------------------------------------------------===//
830 // Uses
831 //===--------------------------------------------------------------------===//
832
833 /// Drop all uses of results of this operation.
834 void dropAllUses() {
835 for (OpResult result : getOpResults())
836 result.dropAllUses();
837 }
838
839 using use_iterator = result_range::use_iterator;
840 using use_range = result_range::use_range;
841
842 use_iterator use_begin() { return getResults().use_begin(); }
843 use_iterator use_end() { return getResults().use_end(); }
844
845 /// Returns a range of all uses, which is useful for iterating over all uses.
846 use_range getUses() { return getResults().getUses(); }
847
848 /// Returns true if this operation has exactly one use.
849 bool hasOneUse() { return llvm::hasSingleElement(C: getUses()); }
850
851 /// Returns true if this operation has no uses.
852 bool use_empty() { return getResults().use_empty(); }
853
854 /// Returns true if the results of this operation are used outside of the
855 /// given block.
856 bool isUsedOutsideOfBlock(Block *block) {
857 return llvm::any_of(Range: getOpResults(), P: [block](OpResult result) {
858 return result.isUsedOutsideOfBlock(block);
859 });
860 }
861
862 //===--------------------------------------------------------------------===//
863 // Users
864 //===--------------------------------------------------------------------===//
865
866 using user_iterator = ValueUserIterator<use_iterator, OpOperand>;
867 using user_range = iterator_range<user_iterator>;
868
869 user_iterator user_begin() { return user_iterator(use_begin()); }
870 user_iterator user_end() { return user_iterator(use_end()); }
871
872 /// Returns a range of all users.
873 user_range getUsers() { return {user_begin(), user_end()}; }
874
875 //===--------------------------------------------------------------------===//
876 // Other
877 //===--------------------------------------------------------------------===//
878
879 /// Emit an error with the op name prefixed, like "'dim' op " which is
880 /// convenient for verifiers.
881 InFlightDiagnostic emitOpError(const Twine &message = {});
882
883 /// Emit an error about fatal conditions with this operation, reporting up to
884 /// any diagnostic handlers that may be listening.
885 InFlightDiagnostic emitError(const Twine &message = {});
886
887 /// Emit a warning about this operation, reporting up to any diagnostic
888 /// handlers that may be listening.
889 InFlightDiagnostic emitWarning(const Twine &message = {});
890
891 /// Emit a remark about this operation, reporting up to any diagnostic
892 /// handlers that may be listening.
893 InFlightDiagnostic emitRemark(const Twine &message = {});
894
895 /// Returns the properties storage size.
896 int getPropertiesStorageSize() const {
897 return ((int)propertiesStorageSize) * 8;
898 }
899 /// Returns the properties storage.
900 OpaqueProperties getPropertiesStorage() {
901 if (propertiesStorageSize)
902 return getPropertiesStorageUnsafe();
903 return {nullptr};
904 }
905 OpaqueProperties getPropertiesStorage() const {
906 if (propertiesStorageSize)
907 return {reinterpret_cast<void *>(const_cast<detail::OpProperties *>(
908 getTrailingObjects<detail::OpProperties>()))};
909 return {nullptr};
910 }
911 /// Returns the properties storage without checking whether properties are
912 /// present.
913 OpaqueProperties getPropertiesStorageUnsafe() {
914 return {
915 reinterpret_cast<void *>(getTrailingObjects<detail::OpProperties>())};
916 }
917
918 /// Return the properties converted to an attribute.
919 /// This is expensive, and mostly useful when dealing with unregistered
920 /// operation. Returns an empty attribute if no properties are present.
921 Attribute getPropertiesAsAttribute();
922
923 /// Set the properties from the provided attribute.
924 /// This is an expensive operation that can fail if the attribute is not
925 /// matching the expectations of the properties for this operation. This is
926 /// mostly useful for unregistered operations or used when parsing the
927 /// generic format. An optional diagnostic emitter can be passed in for richer
928 /// errors, if none is passed then behavior is undefined in error case.
929 LogicalResult
930 setPropertiesFromAttribute(Attribute attr,
931 function_ref<InFlightDiagnostic()> emitError);
932
933 /// Copy properties from an existing other properties object. The two objects
934 /// must be the same type.
935 void copyProperties(OpaqueProperties rhs);
936
937 /// Compute a hash for the op properties (if any).
938 llvm::hash_code hashProperties();
939
940private:
941 //===--------------------------------------------------------------------===//
942 // Ordering
943 //===--------------------------------------------------------------------===//
944
945 /// This value represents an invalid index ordering for an operation within a
946 /// block.
947 static constexpr unsigned kInvalidOrderIdx = -1;
948
949 /// This value represents the stride to use when computing a new order for an
950 /// operation.
951 static constexpr unsigned kOrderStride = 5;
952
953 /// Update the order index of this operation of this operation if necessary,
954 /// potentially recomputing the order of the parent block.
955 void updateOrderIfNecessary();
956
957 /// Returns true if this operation has a valid order.
958 bool hasValidOrder() { return orderIndex != kInvalidOrderIdx; }
959
960private:
961 Operation(Location location, OperationName name, unsigned numResults,
962 unsigned numSuccessors, unsigned numRegions,
963 int propertiesStorageSize, DictionaryAttr attributes,
964 OpaqueProperties properties, bool hasOperandStorage);
965
966 // Operations are deleted through the destroy() member because they are
967 // allocated with malloc.
968 ~Operation();
969
970 /// Returns the additional size necessary for allocating the given objects
971 /// before an Operation in-memory.
972 static size_t prefixAllocSize(unsigned numOutOfLineResults,
973 unsigned numInlineResults) {
974 return sizeof(detail::OutOfLineOpResult) * numOutOfLineResults +
975 sizeof(detail::InlineOpResult) * numInlineResults;
976 }
977 /// Returns the additional size allocated before this Operation in-memory.
978 size_t prefixAllocSize() {
979 unsigned numResults = getNumResults();
980 unsigned numOutOfLineResults = OpResult::getNumTrailing(numResults);
981 unsigned numInlineResults = OpResult::getNumInline(numResults);
982 return prefixAllocSize(numOutOfLineResults, numInlineResults);
983 }
984
985 /// Returns the operand storage object.
986 detail::OperandStorage &getOperandStorage() {
987 assert(hasOperandStorage && "expected operation to have operand storage");
988 return *getTrailingObjects<detail::OperandStorage>();
989 }
990
991 /// Returns a pointer to the use list for the given out-of-line result.
992 detail::OutOfLineOpResult *getOutOfLineOpResult(unsigned resultNumber) {
993 // Out-of-line results are stored in reverse order after (before in memory)
994 // the inline results.
995 return reinterpret_cast<detail::OutOfLineOpResult *>(getInlineOpResult(
996 resultNumber: detail::OpResultImpl::getMaxInlineResults() - 1)) -
997 ++resultNumber;
998 }
999
1000 /// Returns a pointer to the use list for the given inline result.
1001 detail::InlineOpResult *getInlineOpResult(unsigned resultNumber) {
1002 // Inline results are stored in reverse order before the operation in
1003 // memory.
1004 return reinterpret_cast<detail::InlineOpResult *>(this) - ++resultNumber;
1005 }
1006
1007 /// Returns a pointer to the use list for the given result, which may be
1008 /// either inline or out-of-line.
1009 detail::OpResultImpl *getOpResultImpl(unsigned resultNumber) {
1010 assert(resultNumber < getNumResults() &&
1011 "Result number is out of range for operation");
1012 unsigned maxInlineResults = detail::OpResultImpl::getMaxInlineResults();
1013 if (resultNumber < maxInlineResults)
1014 return getInlineOpResult(resultNumber);
1015 return getOutOfLineOpResult(resultNumber: resultNumber - maxInlineResults);
1016 }
1017
1018 /// Provide a 'getParent' method for ilist_node_with_parent methods.
1019 /// We mark it as a const function because ilist_node_with_parent specifically
1020 /// requires a 'getParent() const' method. Once ilist_node removes this
1021 /// constraint, we should drop the const to fit the rest of the MLIR const
1022 /// model.
1023 Block *getParent() const { return block; }
1024
1025 /// Expose a few methods explicitly for the debugger to call for
1026 /// visualization.
1027#ifndef NDEBUG
1028 LLVM_DUMP_METHOD operand_range debug_getOperands() { return getOperands(); }
1029 LLVM_DUMP_METHOD result_range debug_getResults() { return getResults(); }
1030 LLVM_DUMP_METHOD SuccessorRange debug_getSuccessors() {
1031 return getSuccessors();
1032 }
1033 LLVM_DUMP_METHOD MutableArrayRef<Region> debug_getRegions() {
1034 return getRegions();
1035 }
1036#endif
1037
1038 /// The operation block that contains this operation.
1039 Block *block = nullptr;
1040
1041 /// This holds information about the source location the operation was defined
1042 /// or derived from.
1043 Location location;
1044
1045 /// Relative order of this operation in its parent block. Used for
1046 /// O(1) local dominance checks between operations.
1047 mutable unsigned orderIndex = 0;
1048
1049 const unsigned numResults;
1050 const unsigned numSuccs;
1051 const unsigned numRegions : 23;
1052
1053 /// This bit signals whether this operation has an operand storage or not. The
1054 /// operand storage may be elided for operations that are known to never have
1055 /// operands.
1056 bool hasOperandStorage : 1;
1057
1058 /// The size of the storage for properties (if any), divided by 8: since the
1059 /// Properties storage will always be rounded up to the next multiple of 8 we
1060 /// save some bits here.
1061 unsigned char propertiesStorageSize : 8;
1062 /// This is the maximum size we support to allocate properties inline with an
1063 /// operation: this must match the bitwidth above.
1064 static constexpr int64_t propertiesCapacity = 8 * 256;
1065
1066 /// This holds the name of the operation.
1067 OperationName name;
1068
1069 /// This holds general named attributes for the operation.
1070 DictionaryAttr attrs;
1071
1072 // allow ilist_traits access to 'block' field.
1073 friend struct llvm::ilist_traits<Operation>;
1074
1075 // allow block to access the 'orderIndex' field.
1076 friend class Block;
1077
1078 // allow value to access the 'ResultStorage' methods.
1079 friend class Value;
1080
1081 // allow ilist_node_with_parent to access the 'getParent' method.
1082 friend class llvm::ilist_node_with_parent<Operation, Block>;
1083
1084 // This stuff is used by the TrailingObjects template.
1085 friend llvm::TrailingObjects<Operation, detail::OperandStorage,
1086 detail::OpProperties, BlockOperand, Region,
1087 OpOperand>;
1088 size_t numTrailingObjects(OverloadToken<detail::OperandStorage>) const {
1089 return hasOperandStorage ? 1 : 0;
1090 }
1091 size_t numTrailingObjects(OverloadToken<BlockOperand>) const {
1092 return numSuccs;
1093 }
1094 size_t numTrailingObjects(OverloadToken<Region>) const { return numRegions; }
1095 size_t numTrailingObjects(OverloadToken<detail::OpProperties>) const {
1096 return getPropertiesStorageSize();
1097 }
1098};
1099
1100inline raw_ostream &operator<<(raw_ostream &os, const Operation &op) {
1101 const_cast<Operation &>(op).print(os, flags: OpPrintingFlags().useLocalScope());
1102 return os;
1103}
1104
1105} // namespace mlir
1106
1107namespace llvm {
1108/// Cast from an (const) Operation * to a derived operation type.
1109template <typename T>
1110struct CastInfo<T, ::mlir::Operation *>
1111 : public ValueFromPointerCast<T, ::mlir::Operation,
1112 CastInfo<T, ::mlir::Operation *>> {
1113 static bool isPossible(::mlir::Operation *op) { return T::classof(op); }
1114};
1115template <typename T>
1116struct CastInfo<T, const ::mlir::Operation *>
1117 : public ConstStrippingForwardingCast<T, const ::mlir::Operation *,
1118 CastInfo<T, ::mlir::Operation *>> {};
1119
1120/// Cast from an (const) Operation & to a derived operation type.
1121template <typename T>
1122struct CastInfo<T, ::mlir::Operation>
1123 : public NullableValueCastFailed<T>,
1124 public DefaultDoCastIfPossible<T, ::mlir::Operation &,
1125 CastInfo<T, ::mlir::Operation>> {
1126 // Provide isPossible here because here we have the const-stripping from
1127 // ConstStrippingCast.
1128 static bool isPossible(::mlir::Operation &val) { return T::classof(&val); }
1129 static T doCast(::mlir::Operation &val) { return T(&val); }
1130};
1131template <typename T>
1132struct CastInfo<T, const ::mlir::Operation>
1133 : public ConstStrippingForwardingCast<T, const ::mlir::Operation,
1134 CastInfo<T, ::mlir::Operation>> {};
1135
1136/// Cast (const) Operation * to itself. This is helpful to avoid SFINAE in
1137/// templated implementations that should work on both base and derived
1138/// operation types.
1139template <>
1140struct CastInfo<::mlir::Operation *, ::mlir::Operation *>
1141 : public NullableValueCastFailed<::mlir::Operation *>,
1142 public DefaultDoCastIfPossible<
1143 ::mlir::Operation *, ::mlir::Operation *,
1144 CastInfo<::mlir::Operation *, ::mlir::Operation *>> {
1145 static bool isPossible(::mlir::Operation *op) { return true; }
1146 static ::mlir::Operation *doCast(::mlir::Operation *op) { return op; }
1147};
1148template <>
1149struct CastInfo<const ::mlir::Operation *, const ::mlir::Operation *>
1150 : public ConstStrippingForwardingCast<
1151 const ::mlir::Operation *, const ::mlir::Operation *,
1152 CastInfo<::mlir::Operation *, ::mlir::Operation *>> {};
1153} // namespace llvm
1154
1155#endif // MLIR_IR_OPERATION_H
1156

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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