1 //===- OperationSupport.h ---------------------------------------*- 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 a number of support types that Operation and related
10 // classes build on top of.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_IR_OPERATIONSUPPORT_H
15 #define MLIR_IR_OPERATIONSUPPORT_H
16 
17 #include "mlir/IR/BlockSupport.h"
18 #include "mlir/IR/BuiltinAttributes.h"
19 #include "mlir/IR/Location.h"
20 #include "mlir/IR/TypeRange.h"
21 #include "mlir/IR/Types.h"
22 #include "mlir/IR/Value.h"
23 #include "mlir/Support/InterfaceSupport.h"
24 #include "llvm/ADT/BitmaskEnum.h"
25 #include "llvm/ADT/PointerUnion.h"
26 #include "llvm/Support/PointerLikeTypeTraits.h"
27 #include "llvm/Support/TrailingObjects.h"
28 #include <memory>
29 
30 namespace llvm {
31 class BitVector;
32 } // namespace llvm
33 
34 namespace mlir {
35 class Dialect;
36 class DictionaryAttr;
37 class ElementsAttr;
38 class MutableOperandRangeRange;
39 class NamedAttrList;
40 class Operation;
41 struct OperationState;
42 class OpAsmParser;
43 class OpAsmParserResult;
44 class OpAsmPrinter;
45 class OperandRange;
46 class OperandRangeRange;
47 class OpFoldResult;
48 class ParseResult;
49 class Pattern;
50 class Region;
51 class ResultRange;
52 class RewritePattern;
53 class RewritePatternSet;
54 class Type;
55 class Value;
56 class ValueRange;
57 template <typename ValueRangeT>
58 class ValueTypeRange;
59 
60 //===----------------------------------------------------------------------===//
61 // OperationName
62 //===----------------------------------------------------------------------===//
63 
64 class OperationName {
65 public:
66   using GetCanonicalizationPatternsFn =
67       llvm::unique_function<void(RewritePatternSet &, MLIRContext *) const>;
68   using FoldHookFn = llvm::unique_function<LogicalResult(
69       Operation *, ArrayRef<Attribute>, SmallVectorImpl<OpFoldResult> &) const>;
70   using HasTraitFn = llvm::unique_function<bool(TypeID) const>;
71   using ParseAssemblyFn =
72       llvm::unique_function<ParseResult(OpAsmParser &, OperationState &) const>;
73   // Note: RegisteredOperationName is passed as reference here as the derived
74   // class is defined below.
75   using PopulateDefaultAttrsFn = llvm::unique_function<void(
76       const RegisteredOperationName &, NamedAttrList &) const>;
77   using PrintAssemblyFn =
78       llvm::unique_function<void(Operation *, OpAsmPrinter &, StringRef) const>;
79   using VerifyInvariantsFn =
80       llvm::unique_function<LogicalResult(Operation *) const>;
81   using VerifyRegionInvariantsFn =
82       llvm::unique_function<LogicalResult(Operation *) const>;
83 
84 protected:
85   /// This class represents a type erased version of an operation. It contains
86   /// all of the components necessary for opaquely interacting with an
87   /// operation. If the operation is not registered, some of these components
88   /// may not be populated.
89   struct Impl {
ImplImpl90     Impl(StringAttr name)
91         : name(name), dialect(nullptr), interfaceMap(llvm::None) {}
92 
93     /// The name of the operation.
94     StringAttr name;
95 
96     //===------------------------------------------------------------------===//
97     // Registered Operation Info
98 
99     /// The following fields are only populated when the operation is
100     /// registered.
101 
102     /// Returns true if the operation has been registered, i.e. if the
103     /// registration info has been populated.
isRegisteredImpl104     bool isRegistered() const { return dialect; }
105 
106     /// This is the dialect that this operation belongs to.
107     Dialect *dialect;
108 
109     /// The unique identifier of the derived Op class.
110     TypeID typeID;
111 
112     /// A map of interfaces that were registered to this operation.
113     detail::InterfaceMap interfaceMap;
114 
115     /// Internal callback hooks provided by the op implementation.
116     FoldHookFn foldHookFn;
117     GetCanonicalizationPatternsFn getCanonicalizationPatternsFn;
118     HasTraitFn hasTraitFn;
119     ParseAssemblyFn parseAssemblyFn;
120     PopulateDefaultAttrsFn populateDefaultAttrsFn;
121     PrintAssemblyFn printAssemblyFn;
122     VerifyInvariantsFn verifyInvariantsFn;
123     VerifyRegionInvariantsFn verifyRegionInvariantsFn;
124 
125     /// A list of attribute names registered to this operation in StringAttr
126     /// form. This allows for operation classes to use StringAttr for attribute
127     /// lookup/creation/etc., as opposed to raw strings.
128     ArrayRef<StringAttr> attributeNames;
129   };
130 
131 public:
132   OperationName(StringRef name, MLIRContext *context);
133 
134   /// Return if this operation is registered.
isRegistered()135   bool isRegistered() const { return impl->isRegistered(); }
136 
137   /// If this operation is registered, returns the registered information, None
138   /// otherwise.
139   Optional<RegisteredOperationName> getRegisteredInfo() const;
140 
141   /// Returns true if the operation was registered with a particular trait, e.g.
142   /// hasTrait<OperandsAreSignlessIntegerLike>(). Returns false if the operation
143   /// is unregistered.
144   template <template <typename T> class Trait>
hasTrait()145   bool hasTrait() const {
146     return hasTrait(TypeID::get<Trait>());
147   }
hasTrait(TypeID traitID)148   bool hasTrait(TypeID traitID) const {
149     return isRegistered() && impl->hasTraitFn(traitID);
150   }
151 
152   /// Returns true if the operation *might* have the provided trait. This
153   /// means that either the operation is unregistered, or it was registered with
154   /// the provide trait.
155   template <template <typename T> class Trait>
mightHaveTrait()156   bool mightHaveTrait() const {
157     return mightHaveTrait(TypeID::get<Trait>());
158   }
mightHaveTrait(TypeID traitID)159   bool mightHaveTrait(TypeID traitID) const {
160     return !isRegistered() || impl->hasTraitFn(traitID);
161   }
162 
163   /// Returns an instance of the concept object for the given interface if it
164   /// was registered to this operation, null otherwise. This should not be used
165   /// directly.
166   template <typename T>
getInterface()167   typename T::Concept *getInterface() const {
168     return impl->interfaceMap.lookup<T>();
169   }
170 
171   /// Returns true if this operation has the given interface registered to it.
172   template <typename T>
hasInterface()173   bool hasInterface() const {
174     return hasInterface(TypeID::get<T>());
175   }
hasInterface(TypeID interfaceID)176   bool hasInterface(TypeID interfaceID) const {
177     return impl->interfaceMap.contains(interfaceID);
178   }
179 
180   /// Returns true if the operation *might* have the provided interface. This
181   /// means that either the operation is unregistered, or it was registered with
182   /// the provide interface.
183   template <typename T>
mightHaveInterface()184   bool mightHaveInterface() const {
185     return mightHaveInterface(TypeID::get<T>());
186   }
mightHaveInterface(TypeID interfaceID)187   bool mightHaveInterface(TypeID interfaceID) const {
188     return !isRegistered() || hasInterface(interfaceID);
189   }
190 
191   /// Return the dialect this operation is registered to if the dialect is
192   /// loaded in the context, or nullptr if the dialect isn't loaded.
getDialect()193   Dialect *getDialect() const {
194     return isRegistered() ? impl->dialect : impl->name.getReferencedDialect();
195   }
196 
197   /// Return the name of the dialect this operation is registered to.
198   StringRef getDialectNamespace() const;
199 
200   /// Return the operation name with dialect name stripped, if it has one.
stripDialect()201   StringRef stripDialect() const { return getStringRef().split('.').second; }
202 
203   /// Return the name of this operation. This always succeeds.
getStringRef()204   StringRef getStringRef() const { return getIdentifier(); }
205 
206   /// Return the name of this operation as a StringAttr.
getIdentifier()207   StringAttr getIdentifier() const { return impl->name; }
208 
209   void print(raw_ostream &os) const;
210   void dump() const;
211 
212   /// Represent the operation name as an opaque pointer. (Used to support
213   /// PointerLikeTypeTraits).
getAsOpaquePointer()214   void *getAsOpaquePointer() const { return const_cast<Impl *>(impl); }
getFromOpaquePointer(const void * pointer)215   static OperationName getFromOpaquePointer(const void *pointer) {
216     return OperationName(
217         const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
218   }
219 
220   bool operator==(const OperationName &rhs) const { return impl == rhs.impl; }
221   bool operator!=(const OperationName &rhs) const { return !(*this == rhs); }
222 
223 protected:
OperationName(Impl * impl)224   OperationName(Impl *impl) : impl(impl) {}
225 
226   /// The internal implementation of the operation name.
227   Impl *impl;
228 
229   /// Allow access to the Impl struct.
230   friend MLIRContextImpl;
231 };
232 
233 inline raw_ostream &operator<<(raw_ostream &os, OperationName info) {
234   info.print(os);
235   return os;
236 }
237 
238 // Make operation names hashable.
hash_value(OperationName arg)239 inline llvm::hash_code hash_value(OperationName arg) {
240   return llvm::hash_value(arg.getAsOpaquePointer());
241 }
242 
243 //===----------------------------------------------------------------------===//
244 // RegisteredOperationName
245 //===----------------------------------------------------------------------===//
246 
247 /// This is a "type erased" representation of a registered operation. This
248 /// should only be used by things like the AsmPrinter and other things that need
249 /// to be parameterized by generic operation hooks. Most user code should use
250 /// the concrete operation types.
251 class RegisteredOperationName : public OperationName {
252 public:
253   /// Lookup the registered operation information for the given operation.
254   /// Returns None if the operation isn't registered.
255   static Optional<RegisteredOperationName> lookup(StringRef name,
256                                                   MLIRContext *ctx);
257 
258   /// Register a new operation in a Dialect object.
259   /// This constructor is used by Dialect objects when they register the list of
260   /// operations they contain.
261   template <typename T>
insert(Dialect & dialect)262   static void insert(Dialect &dialect) {
263     insert(T::getOperationName(), dialect, TypeID::get<T>(),
264            T::getParseAssemblyFn(), T::getPrintAssemblyFn(),
265            T::getVerifyInvariantsFn(), T::getVerifyRegionInvariantsFn(),
266            T::getFoldHookFn(), T::getGetCanonicalizationPatternsFn(),
267            T::getInterfaceMap(), T::getHasTraitFn(), T::getAttributeNames(),
268            T::getPopulateDefaultAttrsFn());
269   }
270   /// The use of this method is in general discouraged in favor of
271   /// 'insert<CustomOp>(dialect)'.
272   static void
273   insert(StringRef name, Dialect &dialect, TypeID typeID,
274          ParseAssemblyFn &&parseAssembly, PrintAssemblyFn &&printAssembly,
275          VerifyInvariantsFn &&verifyInvariants,
276          VerifyRegionInvariantsFn &&verifyRegionInvariants,
277          FoldHookFn &&foldHook,
278          GetCanonicalizationPatternsFn &&getCanonicalizationPatterns,
279          detail::InterfaceMap &&interfaceMap, HasTraitFn &&hasTrait,
280          ArrayRef<StringRef> attrNames,
281          PopulateDefaultAttrsFn &&populateDefaultAttrs);
282 
283   /// Return the dialect this operation is registered to.
getDialect()284   Dialect &getDialect() const { return *impl->dialect; }
285 
286   /// Return the unique identifier of the derived Op class.
getTypeID()287   TypeID getTypeID() const { return impl->typeID; }
288 
289   /// Use the specified object to parse this ops custom assembly format.
290   ParseResult parseAssembly(OpAsmParser &parser, OperationState &result) const;
291 
292   /// Return the static hook for parsing this operation assembly.
getParseAssemblyFn()293   const ParseAssemblyFn &getParseAssemblyFn() const {
294     return impl->parseAssemblyFn;
295   }
296 
297   /// This hook implements the AsmPrinter for this operation.
printAssembly(Operation * op,OpAsmPrinter & p,StringRef defaultDialect)298   void printAssembly(Operation *op, OpAsmPrinter &p,
299                      StringRef defaultDialect) const {
300     return impl->printAssemblyFn(op, p, defaultDialect);
301   }
302 
303   /// These hooks implement the verifiers for this operation.  It should emits
304   /// an error message and returns failure if a problem is detected, or returns
305   /// success if everything is ok.
verifyInvariants(Operation * op)306   LogicalResult verifyInvariants(Operation *op) const {
307     return impl->verifyInvariantsFn(op);
308   }
verifyRegionInvariants(Operation * op)309   LogicalResult verifyRegionInvariants(Operation *op) const {
310     return impl->verifyRegionInvariantsFn(op);
311   }
312 
313   /// This hook implements a generalized folder for this operation.  Operations
314   /// can implement this to provide simplifications rules that are applied by
315   /// the Builder::createOrFold API and the canonicalization pass.
316   ///
317   /// This is an intentionally limited interface - implementations of this hook
318   /// can only perform the following changes to the operation:
319   ///
320   ///  1. They can leave the operation alone and without changing the IR, and
321   ///     return failure.
322   ///  2. They can mutate the operation in place, without changing anything else
323   ///     in the IR.  In this case, return success.
324   ///  3. They can return a list of existing values that can be used instead of
325   ///     the operation.  In this case, fill in the results list and return
326   ///     success.  The caller will remove the operation and use those results
327   ///     instead.
328   ///
329   /// This allows expression of some simple in-place canonicalizations (e.g.
330   /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as
331   /// generalized constant folding.
foldHook(Operation * op,ArrayRef<Attribute> operands,SmallVectorImpl<OpFoldResult> & results)332   LogicalResult foldHook(Operation *op, ArrayRef<Attribute> operands,
333                          SmallVectorImpl<OpFoldResult> &results) const {
334     return impl->foldHookFn(op, operands, results);
335   }
336 
337   /// This hook returns any canonicalization pattern rewrites that the operation
338   /// supports, for use by the canonicalization pass.
getCanonicalizationPatterns(RewritePatternSet & results,MLIRContext * context)339   void getCanonicalizationPatterns(RewritePatternSet &results,
340                                    MLIRContext *context) const {
341     return impl->getCanonicalizationPatternsFn(results, context);
342   }
343 
344   /// Attach the given models as implementations of the corresponding interfaces
345   /// for the concrete operation.
346   template <typename... Models>
attachInterface()347   void attachInterface() {
348     impl->interfaceMap.insert<Models...>();
349   }
350 
351   /// Returns true if the operation has a particular trait.
352   template <template <typename T> class Trait>
hasTrait()353   bool hasTrait() const {
354     return hasTrait(TypeID::get<Trait>());
355   }
356 
357   /// Returns true if the operation has a particular trait.
hasTrait(TypeID traitID)358   bool hasTrait(TypeID traitID) const { return impl->hasTraitFn(traitID); }
359 
360   /// Return the list of cached attribute names registered to this operation.
361   /// The order of attributes cached here is unique to each type of operation,
362   /// and the interpretation of this attribute list should generally be driven
363   /// by the respective operation. In many cases, this caching removes the need
364   /// to use the raw string name of a known attribute.
365   ///
366   /// For example the ODS generator, with an op defining the following
367   /// attributes:
368   ///
369   ///   let arguments = (ins I32Attr:$attr1, I32Attr:$attr2);
370   ///
371   /// ... may produce an order here of ["attr1", "attr2"]. This allows for the
372   /// ODS generator to directly access the cached name for a known attribute,
373   /// greatly simplifying the cost and complexity of attribute usage produced by
374   /// the generator.
375   ///
getAttributeNames()376   ArrayRef<StringAttr> getAttributeNames() const {
377     return impl->attributeNames;
378   }
379 
380   /// This hook implements the method to populate defaults attributes that are
381   /// unset.
382   void populateDefaultAttrs(NamedAttrList &attrs) const;
383 
384   /// Represent the operation name as an opaque pointer. (Used to support
385   /// PointerLikeTypeTraits).
getFromOpaquePointer(const void * pointer)386   static RegisteredOperationName getFromOpaquePointer(const void *pointer) {
387     return RegisteredOperationName(
388         const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
389   }
390 
391 private:
RegisteredOperationName(Impl * impl)392   RegisteredOperationName(Impl *impl) : OperationName(impl) {}
393 
394   /// Allow access to the constructor.
395   friend OperationName;
396 };
397 
398 inline Optional<RegisteredOperationName>
getRegisteredInfo()399 OperationName::getRegisteredInfo() const {
400   return isRegistered() ? RegisteredOperationName(impl)
401                         : Optional<RegisteredOperationName>();
402 }
403 
404 //===----------------------------------------------------------------------===//
405 // Attribute Dictionary-Like Interface
406 //===----------------------------------------------------------------------===//
407 
408 /// Attribute collections provide a dictionary-like interface. Define common
409 /// lookup functions.
410 namespace impl {
411 
412 /// Unsorted string search or identifier lookups are linear scans.
413 template <typename IteratorT, typename NameT>
findAttrUnsorted(IteratorT first,IteratorT last,NameT name)414 std::pair<IteratorT, bool> findAttrUnsorted(IteratorT first, IteratorT last,
415                                             NameT name) {
416   for (auto it = first; it != last; ++it)
417     if (it->getName() == name)
418       return {it, true};
419   return {last, false};
420 }
421 
422 /// Using llvm::lower_bound requires an extra string comparison to check whether
423 /// the returned iterator points to the found element or whether it indicates
424 /// the lower bound. Skip this redundant comparison by checking if `compare ==
425 /// 0` during the binary search.
426 template <typename IteratorT>
findAttrSorted(IteratorT first,IteratorT last,StringRef name)427 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
428                                           StringRef name) {
429   ptrdiff_t length = std::distance(first, last);
430 
431   while (length > 0) {
432     ptrdiff_t half = length / 2;
433     IteratorT mid = first + half;
434     int compare = mid->getName().strref().compare(name);
435     if (compare < 0) {
436       first = mid + 1;
437       length = length - half - 1;
438     } else if (compare > 0) {
439       length = half;
440     } else {
441       return {mid, true};
442     }
443   }
444   return {first, false};
445 }
446 
447 /// StringAttr lookups on large attribute lists will switch to string binary
448 /// search. String binary searches become significantly faster than linear scans
449 /// with the identifier when the attribute list becomes very large.
450 template <typename IteratorT>
findAttrSorted(IteratorT first,IteratorT last,StringAttr name)451 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
452                                           StringAttr name) {
453   constexpr unsigned kSmallAttributeList = 16;
454   if (std::distance(first, last) > kSmallAttributeList)
455     return findAttrSorted(first, last, name.strref());
456   return findAttrUnsorted(first, last, name);
457 }
458 
459 /// Get an attribute from a sorted range of named attributes. Returns null if
460 /// the attribute was not found.
461 template <typename IteratorT, typename NameT>
getAttrFromSortedRange(IteratorT first,IteratorT last,NameT name)462 Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
463   std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
464   return result.second ? result.first->getValue() : Attribute();
465 }
466 
467 /// Get an attribute from a sorted range of named attributes. Returns None if
468 /// the attribute was not found.
469 template <typename IteratorT, typename NameT>
470 Optional<NamedAttribute>
getNamedAttrFromSortedRange(IteratorT first,IteratorT last,NameT name)471 getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
472   std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
473   return result.second ? *result.first : Optional<NamedAttribute>();
474 }
475 
476 } // namespace impl
477 
478 //===----------------------------------------------------------------------===//
479 // NamedAttrList
480 //===----------------------------------------------------------------------===//
481 
482 /// NamedAttrList is array of NamedAttributes that tracks whether it is sorted
483 /// and does some basic work to remain sorted.
484 class NamedAttrList {
485 public:
486   using iterator = SmallVectorImpl<NamedAttribute>::iterator;
487   using const_iterator = SmallVectorImpl<NamedAttribute>::const_iterator;
488   using reference = NamedAttribute &;
489   using const_reference = const NamedAttribute &;
490   using size_type = size_t;
491 
NamedAttrList()492   NamedAttrList() : dictionarySorted({}, true) {}
NamedAttrList(llvm::NoneType none)493   NamedAttrList(llvm::NoneType none) : NamedAttrList() {}
494   NamedAttrList(ArrayRef<NamedAttribute> attributes);
495   NamedAttrList(DictionaryAttr attributes);
496   NamedAttrList(const_iterator inStart, const_iterator inEnd);
497 
498   template <typename Container>
NamedAttrList(const Container & vec)499   NamedAttrList(const Container &vec)
500       : NamedAttrList(ArrayRef<NamedAttribute>(vec)) {}
501 
502   bool operator!=(const NamedAttrList &other) const {
503     return !(*this == other);
504   }
505   bool operator==(const NamedAttrList &other) const {
506     return attrs == other.attrs;
507   }
508 
509   /// Add an attribute with the specified name.
510   void append(StringRef name, Attribute attr);
511 
512   /// Add an attribute with the specified name.
append(StringAttr name,Attribute attr)513   void append(StringAttr name, Attribute attr) {
514     append(NamedAttribute(name, attr));
515   }
516 
517   /// Append the given named attribute.
append(NamedAttribute attr)518   void append(NamedAttribute attr) { push_back(attr); }
519 
520   /// Add an array of named attributes.
521   template <typename RangeT>
append(RangeT && newAttributes)522   void append(RangeT &&newAttributes) {
523     append(std::begin(newAttributes), std::end(newAttributes));
524   }
525 
526   /// Add a range of named attributes.
527   template <typename IteratorT,
528             typename = std::enable_if_t<std::is_convertible<
529                 typename std::iterator_traits<IteratorT>::iterator_category,
530                 std::input_iterator_tag>::value>>
append(IteratorT inStart,IteratorT inEnd)531   void append(IteratorT inStart, IteratorT inEnd) {
532     // TODO: expand to handle case where values appended are in order & after
533     // end of current list.
534     dictionarySorted.setPointerAndInt(nullptr, false);
535     attrs.append(inStart, inEnd);
536   }
537 
538   /// Replaces the attributes with new list of attributes.
539   void assign(const_iterator inStart, const_iterator inEnd);
540 
541   /// Replaces the attributes with new list of attributes.
assign(ArrayRef<NamedAttribute> range)542   void assign(ArrayRef<NamedAttribute> range) {
543     assign(range.begin(), range.end());
544   }
545 
empty()546   bool empty() const { return attrs.empty(); }
547 
reserve(size_type N)548   void reserve(size_type N) { attrs.reserve(N); }
549 
550   /// Add an attribute with the specified name.
551   void push_back(NamedAttribute newAttribute);
552 
553   /// Pop last element from list.
pop_back()554   void pop_back() { attrs.pop_back(); }
555 
556   /// Returns an entry with a duplicate name the list, if it exists, else
557   /// returns llvm::None.
558   Optional<NamedAttribute> findDuplicate() const;
559 
560   /// Return a dictionary attribute for the underlying dictionary. This will
561   /// return an empty dictionary attribute if empty rather than null.
562   DictionaryAttr getDictionary(MLIRContext *context) const;
563 
564   /// Return all of the attributes on this operation.
565   ArrayRef<NamedAttribute> getAttrs() const;
566 
567   /// Return the specified attribute if present, null otherwise.
568   Attribute get(StringAttr name) const;
569   Attribute get(StringRef name) const;
570 
571   /// Return the specified named attribute if present, None otherwise.
572   Optional<NamedAttribute> getNamed(StringRef name) const;
573   Optional<NamedAttribute> getNamed(StringAttr name) const;
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   /// Returns the previous attribute value of `name`, or null if no
578   /// attribute previously existed with `name`.
579   Attribute set(StringAttr name, Attribute value);
580   Attribute set(StringRef name, Attribute value);
581 
582   /// Erase the attribute with the given name from the list. Return the
583   /// attribute that was erased, or nullptr if there was no attribute with such
584   /// name.
585   Attribute erase(StringAttr name);
586   Attribute erase(StringRef name);
587 
begin()588   iterator begin() { return attrs.begin(); }
end()589   iterator end() { return attrs.end(); }
begin()590   const_iterator begin() const { return attrs.begin(); }
end()591   const_iterator end() const { return attrs.end(); }
592 
593   NamedAttrList &operator=(const SmallVectorImpl<NamedAttribute> &rhs);
594   operator ArrayRef<NamedAttribute>() const;
595 
596 private:
597   /// Return whether the attributes are sorted.
isSorted()598   bool isSorted() const { return dictionarySorted.getInt(); }
599 
600   /// Erase the attribute at the given iterator position.
601   Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
602 
603   /// Lookup an attribute in the list.
604   template <typename AttrListT, typename NameT>
findAttr(AttrListT & attrs,NameT name)605   static auto findAttr(AttrListT &attrs, NameT name) {
606     return attrs.isSorted()
607                ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
608                : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
609   }
610 
611   // These are marked mutable as they may be modified (e.g., sorted)
612   mutable SmallVector<NamedAttribute, 4> attrs;
613   // Pair with cached DictionaryAttr and status of whether attrs is sorted.
614   // Note: just because sorted does not mean a DictionaryAttr has been created
615   // but the case where there is a DictionaryAttr but attrs isn't sorted should
616   // not occur.
617   mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
618 };
619 
620 //===----------------------------------------------------------------------===//
621 // OperationState
622 //===----------------------------------------------------------------------===//
623 
624 /// This represents an operation in an abstracted form, suitable for use with
625 /// the builder APIs.  This object is a large and heavy weight object meant to
626 /// be used as a temporary object on the stack.  It is generally unwise to put
627 /// this in a collection.
628 struct OperationState {
629   Location location;
630   OperationName name;
631   SmallVector<Value, 4> operands;
632   /// Types of the results of this operation.
633   SmallVector<Type, 4> types;
634   NamedAttrList attributes;
635   /// Successors of this operation and their respective operands.
636   SmallVector<Block *, 1> successors;
637   /// Regions that the op will hold.
638   SmallVector<std::unique_ptr<Region>, 1> regions;
639 
640 public:
641   OperationState(Location location, StringRef name);
642   OperationState(Location location, OperationName name);
643 
644   OperationState(Location location, OperationName name, ValueRange operands,
645                  TypeRange types, ArrayRef<NamedAttribute> attributes,
646                  BlockRange successors = {},
647                  MutableArrayRef<std::unique_ptr<Region>> regions = {});
648   OperationState(Location location, StringRef name, ValueRange operands,
649                  TypeRange types, ArrayRef<NamedAttribute> attributes,
650                  BlockRange successors = {},
651                  MutableArrayRef<std::unique_ptr<Region>> regions = {});
652 
653   void addOperands(ValueRange newOperands);
654 
addTypesOperationState655   void addTypes(ArrayRef<Type> newTypes) {
656     types.append(newTypes.begin(), newTypes.end());
657   }
658   template <typename RangeT>
659   std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
addTypesOperationState660   addTypes(RangeT &&newTypes) {
661     types.append(newTypes.begin(), newTypes.end());
662   }
663 
664   /// Add an attribute with the specified name.
addAttributeOperationState665   void addAttribute(StringRef name, Attribute attr) {
666     addAttribute(StringAttr::get(getContext(), name), attr);
667   }
668 
669   /// Add an attribute with the specified name.
addAttributeOperationState670   void addAttribute(StringAttr name, Attribute attr) {
671     attributes.append(name, attr);
672   }
673 
674   /// Add an array of named attributes.
addAttributesOperationState675   void addAttributes(ArrayRef<NamedAttribute> newAttributes) {
676     attributes.append(newAttributes);
677   }
678 
addSuccessorsOperationState679   void addSuccessors(Block *successor) { successors.push_back(successor); }
680   void addSuccessors(BlockRange newSuccessors);
681 
682   /// Create a region that should be attached to the operation.  These regions
683   /// can be filled in immediately without waiting for Operation to be
684   /// created.  When it is, the region bodies will be transferred.
685   Region *addRegion();
686 
687   /// Take a region that should be attached to the Operation.  The body of the
688   /// region will be transferred when the Operation is constructed.  If the
689   /// region is null, a new empty region will be attached to the Operation.
690   void addRegion(std::unique_ptr<Region> &&region);
691 
692   /// Take ownership of a set of regions that should be attached to the
693   /// Operation.
694   void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
695 
696   /// Get the context held by this operation state.
getContextOperationState697   MLIRContext *getContext() const { return location->getContext(); }
698 };
699 
700 //===----------------------------------------------------------------------===//
701 // OperandStorage
702 //===----------------------------------------------------------------------===//
703 
704 namespace detail {
705 /// This class handles the management of operation operands. Operands are
706 /// stored either in a trailing array, or a dynamically resizable vector.
707 class alignas(8) OperandStorage {
708 public:
709   OperandStorage(Operation *owner, OpOperand *trailingOperands,
710                  ValueRange values);
711   ~OperandStorage();
712 
713   /// Replace the operands contained in the storage with the ones provided in
714   /// 'values'.
715   void setOperands(Operation *owner, ValueRange values);
716 
717   /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
718   /// with the ones provided in 'operands'. 'operands' may be smaller or larger
719   /// than the range pointed to by 'start'+'length'.
720   void setOperands(Operation *owner, unsigned start, unsigned length,
721                    ValueRange operands);
722 
723   /// Erase the operands held by the storage within the given range.
724   void eraseOperands(unsigned start, unsigned length);
725 
726   /// Erase the operands held by the storage that have their corresponding bit
727   /// set in `eraseIndices`.
728   void eraseOperands(const BitVector &eraseIndices);
729 
730   /// Get the operation operands held by the storage.
getOperands()731   MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
732 
733   /// Return the number of operands held in the storage.
size()734   unsigned size() { return numOperands; }
735 
736 private:
737   /// Resize the storage to the given size. Returns the array containing the new
738   /// operands.
739   MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
740 
741   /// The total capacity number of operands that the storage can hold.
742   unsigned capacity : 31;
743   /// A flag indicating if the operand storage was dynamically allocated, as
744   /// opposed to inlined into the owning operation.
745   unsigned isStorageDynamic : 1;
746   /// The number of operands within the storage.
747   unsigned numOperands;
748   /// A pointer to the operand storage.
749   OpOperand *operandStorage;
750 };
751 } // namespace detail
752 
753 //===----------------------------------------------------------------------===//
754 // OpPrintingFlags
755 //===----------------------------------------------------------------------===//
756 
757 /// Set of flags used to control the behavior of the various IR print methods
758 /// (e.g. Operation::Print).
759 class OpPrintingFlags {
760 public:
761   OpPrintingFlags();
OpPrintingFlags(llvm::NoneType)762   OpPrintingFlags(llvm::NoneType) : OpPrintingFlags() {}
763 
764   /// Enables the elision of large elements attributes by printing a lexically
765   /// valid but otherwise meaningless form instead of the element data. The
766   /// `largeElementLimit` is used to configure what is considered to be a
767   /// "large" ElementsAttr by providing an upper limit to the number of
768   /// elements.
769   OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
770 
771   /// Enable printing of debug information. If 'prettyForm' is set to true,
772   /// debug information is printed in a more readable 'pretty' form. Note: The
773   /// IR generated with 'prettyForm' is not parsable.
774   OpPrintingFlags &enableDebugInfo(bool prettyForm = false);
775 
776   /// Always print operations in the generic form.
777   OpPrintingFlags &printGenericOpForm();
778 
779   /// Do not verify the operation when using custom operation printers.
780   OpPrintingFlags &assumeVerified();
781 
782   /// Use local scope when printing the operation. This allows for using the
783   /// printer in a more localized and thread-safe setting, but may not
784   /// necessarily be identical to what the IR will look like when dumping
785   /// the full module.
786   OpPrintingFlags &useLocalScope();
787 
788   /// Print users of values as comments.
789   OpPrintingFlags &printValueUsers();
790 
791   /// Return if the given ElementsAttr should be elided.
792   bool shouldElideElementsAttr(ElementsAttr attr) const;
793 
794   /// Return the size limit for printing large ElementsAttr.
795   Optional<int64_t> getLargeElementsAttrLimit() const;
796 
797   /// Return if debug information should be printed.
798   bool shouldPrintDebugInfo() const;
799 
800   /// Return if debug information should be printed in the pretty form.
801   bool shouldPrintDebugInfoPrettyForm() const;
802 
803   /// Return if operations should be printed in the generic form.
804   bool shouldPrintGenericOpForm() const;
805 
806   /// Return if operation verification should be skipped.
807   bool shouldAssumeVerified() const;
808 
809   /// Return if the printer should use local scope when dumping the IR.
810   bool shouldUseLocalScope() const;
811 
812   /// Return if the printer should print users of values.
813   bool shouldPrintValueUsers() const;
814 
815 private:
816   /// Elide large elements attributes if the number of elements is larger than
817   /// the upper limit.
818   Optional<int64_t> elementsAttrElementLimit;
819 
820   /// Print debug information.
821   bool printDebugInfoFlag : 1;
822   bool printDebugInfoPrettyFormFlag : 1;
823 
824   /// Print operations in the generic form.
825   bool printGenericOpFormFlag : 1;
826 
827   /// Skip operation verification.
828   bool assumeVerifiedFlag : 1;
829 
830   /// Print operations with numberings local to the current operation.
831   bool printLocalScope : 1;
832 
833   /// Print users of values.
834   bool printValueUsersFlag : 1;
835 };
836 
837 //===----------------------------------------------------------------------===//
838 // Operation Equivalency
839 //===----------------------------------------------------------------------===//
840 
841 /// This class provides utilities for computing if two operations are
842 /// equivalent.
843 struct OperationEquivalence {
844   enum Flags {
845     None = 0,
846 
847     // When provided, the location attached to the operation are ignored.
848     IgnoreLocations = 1,
849 
850     LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
851   };
852 
853   /// Compute a hash for the given operation.
854   /// The `hashOperands` and `hashResults` callbacks are expected to return a
855   /// unique hash_code for a given Value.
856   static llvm::hash_code computeHash(
857       Operation *op,
858       function_ref<llvm::hash_code(Value)> hashOperands =
859           [](Value v) { return hash_value(v); },
860       function_ref<llvm::hash_code(Value)> hashResults =
861           [](Value v) { return hash_value(v); },
862       Flags flags = Flags::None);
863 
864   /// Helper that can be used with `computeHash` above to ignore operation
865   /// operands/result mapping.
ignoreHashValueOperationEquivalence866   static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
867   /// Helper that can be used with `computeHash` above to ignore operation
868   /// operands/result mapping.
directHashValueOperationEquivalence869   static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
870 
871   /// Compare two operations and return if they are equivalent.
872   /// `mapOperands` and `mapResults` are optional callbacks that allows the
873   /// caller to check the mapping of SSA value between the lhs and rhs
874   /// operations. It is expected to return success if the mapping is valid and
875   /// failure if it conflicts with a previous mapping.
876   static bool
877   isEquivalentTo(Operation *lhs, Operation *rhs,
878                  function_ref<LogicalResult(Value, Value)> mapOperands,
879                  function_ref<LogicalResult(Value, Value)> mapResults,
880                  Flags flags = Flags::None);
881 
882   /// Helper that can be used with `isEquivalentTo` above to ignore operation
883   /// operands/result mapping.
ignoreValueEquivalenceOperationEquivalence884   static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs) {
885     return success();
886   }
887   /// Helper that can be used with `isEquivalentTo` above to ignore operation
888   /// operands/result mapping.
exactValueMatchOperationEquivalence889   static LogicalResult exactValueMatch(Value lhs, Value rhs) {
890     return success(lhs == rhs);
891   }
892 };
893 
894 /// Enable Bitmask enums for OperationEquivalence::Flags.
895 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
896 
897 } // namespace mlir
898 
899 namespace llvm {
900 template <>
901 struct DenseMapInfo<mlir::OperationName> {
902   static mlir::OperationName getEmptyKey() {
903     void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
904     return mlir::OperationName::getFromOpaquePointer(pointer);
905   }
906   static mlir::OperationName getTombstoneKey() {
907     void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
908     return mlir::OperationName::getFromOpaquePointer(pointer);
909   }
910   static unsigned getHashValue(mlir::OperationName val) {
911     return DenseMapInfo<void *>::getHashValue(val.getAsOpaquePointer());
912   }
913   static bool isEqual(mlir::OperationName lhs, mlir::OperationName rhs) {
914     return lhs == rhs;
915   }
916 };
917 template <>
918 struct DenseMapInfo<mlir::RegisteredOperationName>
919     : public DenseMapInfo<mlir::OperationName> {
920   static mlir::RegisteredOperationName getEmptyKey() {
921     void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
922     return mlir::RegisteredOperationName::getFromOpaquePointer(pointer);
923   }
924   static mlir::RegisteredOperationName getTombstoneKey() {
925     void *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
926     return mlir::RegisteredOperationName::getFromOpaquePointer(pointer);
927   }
928 };
929 
930 template <>
931 struct PointerLikeTypeTraits<mlir::OperationName> {
932   static inline void *getAsVoidPointer(mlir::OperationName I) {
933     return const_cast<void *>(I.getAsOpaquePointer());
934   }
935   static inline mlir::OperationName getFromVoidPointer(void *P) {
936     return mlir::OperationName::getFromOpaquePointer(P);
937   }
938   static constexpr int NumLowBitsAvailable =
939       PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
940 };
941 template <>
942 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
943     : public PointerLikeTypeTraits<mlir::OperationName> {
944   static inline mlir::RegisteredOperationName getFromVoidPointer(void *P) {
945     return mlir::RegisteredOperationName::getFromOpaquePointer(P);
946   }
947 };
948 
949 } // namespace llvm
950 
951 #endif
952