18 #include "llvm/Support/SHA1.h" 
   29   assign(attributes.begin(), attributes.end());
 
   35   dictionarySorted.setPointerAndInt(attributes, 
true);
 
   45   std::optional<NamedAttribute> duplicate =
 
   46       DictionaryAttr::findDuplicate(attrs, isSorted());
 
   50     dictionarySorted.setPointerAndInt(
nullptr, 
true);
 
   56     DictionaryAttr::sortInPlace(attrs);
 
   57     dictionarySorted.setPointerAndInt(
nullptr, 
true);
 
   59   if (!dictionarySorted.getPointer())
 
   60     dictionarySorted.setPointer(DictionaryAttr::getWithSorted(context, attrs));
 
   61   return llvm::cast<DictionaryAttr>(dictionarySorted.getPointer());
 
   67   dictionarySorted.setPointerAndInt(
nullptr, 
true);
 
   72     dictionarySorted.setInt(attrs.empty() || attrs.back() < newAttribute);
 
   73   dictionarySorted.setPointer(
nullptr);
 
   74   attrs.push_back(newAttribute);
 
   79   auto it = findAttr(*
this, name);
 
   80   return it.second ? it.first->getValue() : 
Attribute();
 
   83   auto it = findAttr(*
this, name);
 
   84   return it.second ? it.first->getValue() : 
Attribute();
 
   89   auto it = findAttr(*
this, name);
 
   90   return it.second ? *it.first : std::optional<NamedAttribute>();
 
   93   auto it = findAttr(*
this, name);
 
   94   return it.second ? *it.first : std::optional<NamedAttribute>();
 
  100   assert(value && 
"attributes may never be null");
 
  104   auto it = findAttr(*
this, name);
 
  108     Attribute oldValue = it.first->getValue();
 
  109     if (it.first->getValue() != value) {
 
  110       it.first->setValue(value);
 
  113       dictionarySorted.setPointer(
nullptr);
 
  120     it = findAttr(*
this, name.strref());
 
  121   attrs.insert(it.first, {name, value});
 
  123   dictionarySorted.setPointer(
nullptr);
 
  128   assert(value && 
"attributes may never be null");
 
  137   dictionarySorted.setPointer(
nullptr);
 
  142   auto it = findAttr(*
this, name);
 
  143   return it.second ? eraseImpl(it.first) : 
Attribute();
 
  147   auto it = findAttr(*
this, name);
 
  148   return it.second ? eraseImpl(it.first) : 
Attribute();
 
  153   assign(rhs.begin(), rhs.end());
 
  164     : location(location), name(name, location->
getContext()) {}
 
  167     : location(location), name(name) {}
 
  174     : location(location), name(name),
 
  175       operands(operands.begin(), operands.end()),
 
  176       types(types.begin(), types.end()),
 
  177       attributes(attributes.begin(), attributes.end()),
 
  178       successors(successors.begin(), successors.end()) {
 
  179   for (std::unique_ptr<Region> &r : 
regions)
 
  180     this->regions.push_back(std::move(r));
 
  188                      operands, types, attributes, successors, regions) {}
 
  192     propertiesDeleter(properties);
 
  207   operands.append(newOperands.begin(), newOperands.end());
 
  211   successors.append(newSuccessors.begin(), newSuccessors.end());
 
  220   regions.push_back(std::move(region));
 
  225   for (std::unique_ptr<Region> ®ion : 
regions)
 
  236     : isStorageDynamic(false), operandStorage(trailingOperands) {
 
  237   numOperands = capacity = values.size();
 
  238   for (
unsigned i = 0; i < numOperands; ++i)
 
  239     new (&operandStorage[i]) 
OpOperand(owner, values[i]);
 
  243   for (
auto &operand : getOperands())
 
  244     operand.~OpOperand();
 
  247   if (isStorageDynamic)
 
  248     free(operandStorage);
 
  255   for (
unsigned i = 0, e = values.size(); i != e; ++i)
 
  256     storageOperands[i].set(values[i]);
 
  265   unsigned newSize = operands.size();
 
  266   if (newSize == length) {
 
  268     for (
unsigned i = 0, e = length; i != e; ++i)
 
  269       storageOperands[start + i].set(operands[i]);
 
  274   if (newSize < length) {
 
  275     eraseOperands(start + operands.size(), length - newSize);
 
  276     setOperands(owner, start, newSize, operands);
 
  280   auto storageOperands = resize(owner, size() + (newSize - length));
 
  283   unsigned rotateSize = storageOperands.size() - (start + length);
 
  284   auto rbegin = storageOperands.rbegin();
 
  285   std::rotate(rbegin, std::next(rbegin, newSize - length), rbegin + rotateSize);
 
  288   for (
unsigned i = 0, e = operands.size(); i != e; ++i)
 
  289     storageOperands[start + i].set(operands[i]);
 
  295   assert((start + length) <= operands.size());
 
  296   numOperands -= length;
 
  299   if (start != numOperands) {
 
  300     auto *indexIt = std::next(operands.begin(), start);
 
  301     std::rotate(indexIt, std::next(indexIt, length), operands.end());
 
  303   for (
unsigned i = 0; i != length; ++i)
 
  309   assert(eraseIndices.size() == operands.size());
 
  312   int firstErasedIndice = eraseIndices.find_first();
 
  313   if (firstErasedIndice == -1)
 
  317   numOperands = firstErasedIndice;
 
  318   for (
unsigned i = firstErasedIndice + 1, e = operands.size(); i < e; ++i)
 
  319     if (!eraseIndices.test(i))
 
  320       operands[numOperands++] = std::move(operands[i]);
 
  321   for (
OpOperand &operand : operands.drop_front(numOperands))
 
  322     operand.~OpOperand();
 
  332   if (newSize <= numOperands) {
 
  335     for (
unsigned i = newSize; i != numOperands; ++i)
 
  337     numOperands = newSize;
 
  338     return origOperands.take_front(newSize);
 
  342   if (newSize <= capacity) {
 
  343     OpOperand *opBegin = origOperands.data();
 
  344     for (
unsigned e = newSize; numOperands != e; ++numOperands)
 
  345       new (&opBegin[numOperands]) 
OpOperand(owner);
 
  350   unsigned newCapacity =
 
  351       std::max(
unsigned(llvm::NextPowerOf2(capacity + 2)), newSize);
 
  357   std::uninitialized_move(origOperands.begin(), origOperands.end(),
 
  358                           newOperands.begin());
 
  361   for (
auto &operand : origOperands)
 
  362     operand.~OpOperand();
 
  365   for (
unsigned e = newSize; numOperands != e; ++numOperands)
 
  366     new (&newOperands[numOperands]) 
OpOperand(owner);
 
  369   if (isStorageDynamic)
 
  370     free(operandStorage);
 
  373   operandStorage = newOperandStorage;
 
  374   capacity = newCapacity;
 
  375   isStorageDynamic = 
true;
 
  388   assert(!empty() && 
"range must not be empty");
 
  389   return base->getOperandNumber();
 
  407   const OwnerT &owner = 
getBase();
 
  409   return OperandRange(owner.first, llvm::sum_of(sizeData));
 
  412 OperandRange OperandRangeRange::dereference(
const OwnerT &
object,
 
  415   uint32_t startIndex = llvm::sum_of(sizeData.take_front(index));
 
  416   return OperandRange(
object.first + startIndex, *(sizeData.begin() + index));
 
  426     Operation *owner, 
unsigned start, 
unsigned length,
 
  428     : owner(owner), start(start), length(length),
 
  429       operandSegments(operandSegments) {
 
  430   assert((start + length) <= owner->
getNumOperands() && 
"invalid range");
 
  438                           opOperand.getOperandNumber(),
 
  444                            std::optional<OperandSegment> segment)
 const {
 
  445   assert((subStart + subLen) <= length && 
"invalid sub-range");
 
  449     subSlice.operandSegments.push_back(*segment);
 
  458   updateLength(length + values.size());
 
  464   if (length != values.size())
 
  465     updateLength(values.size());
 
  480   assert((subStart + subLen) <= length && 
"invalid sub-range");
 
  484   updateLength(length - subLen);
 
  502   return getAsOperandRange();
 
  515 void MutableOperandRange::updateLength(
unsigned newLength) {
 
  516   int32_t diff = int32_t(newLength) - int32_t(length);
 
  521     auto attr = llvm::cast<DenseI32ArrayAttr>(segment.second.getValue());
 
  523     segments[segment.first] += diff;
 
  524     segment.second.setValue(
 
  526     owner->
setAttr(segment.second.getName(), segment.second.getValue());
 
  531   assert(index < length && 
"index is out of bounds");
 
  550           OwnerT(operands, operandSegmentAttr), 0,
 
  565       llvm::cast<DenseI32ArrayAttr>(
object.second.getValue());
 
  566   uint32_t startIndex = llvm::sum_of(sizeData.take_front(index));
 
  567   return object.first.slice(
 
  568       startIndex, *(sizeData.begin() + index),
 
  600     : it(end ? results.end() : results.begin()), endIt(results.end()) {
 
  603     skipOverResultsWithNoUsers();
 
  609   if (use != (*it).use_end())
 
  611   if (use == (*it).use_end()) {
 
  613     skipOverResultsWithNoUsers();
 
  618 void ResultRange::UseIterator::skipOverResultsWithNoUsers() {
 
  619   while (it != endIt && (*it).use_empty())
 
  627     use = (*it).use_begin();
 
  653   if (
const auto *value = llvm::dyn_cast_if_present<const Value *>(owner))
 
  654     return {value + index};
 
  655   if (
auto *operand = llvm::dyn_cast_if_present<OpOperand *>(owner))
 
  656     return {operand + index};
 
  657   return cast<detail::OpResultImpl *>(owner)->getNextResultAtOffset(index);
 
  660 Value ValueRange::dereference_iterator(
const OwnerT &owner, ptrdiff_t index) {
 
  661   if (
const auto *value = llvm::dyn_cast_if_present<const Value *>(owner))
 
  663   if (
auto *operand = llvm::dyn_cast_if_present<OpOperand *>(owner))
 
  664     return operand[index].get();
 
  665   return cast<detail::OpResultImpl *>(owner)->getNextResultAtOffset(index);
 
  679   DictionaryAttr dictAttrs;
 
  680   if (!(flags & Flags::IgnoreDiscardableAttrs))
 
  682   llvm::hash_code hash =
 
  684   if (!(flags & Flags::IgnoreProperties))
 
  688   if (!(flags & Flags::IgnoreLocations))
 
  689     hash = llvm::hash_combine(hash, op->
getLoc());
 
  694     size_t operandHash = hashOperands(op->
getOperand(0));
 
  695     for (
auto operand : op->
getOperands().drop_front())
 
  696       operandHash += hashOperands(operand);
 
  697     hash = llvm::hash_combine(hash, operandHash);
 
  700       hash = llvm::hash_combine(hash, hashOperands(operand));
 
  705     hash = llvm::hash_combine(hash, hashResults(result));
 
  715         checkCommutativeEquivalent) {
 
  717   auto blocksEquivalent = [&](
Block &lBlock, 
Block &rBlock) {
 
  723     auto insertion = blocksMap.insert({&lBlock, &rBlock});
 
  724     if (insertion.first->getSecond() != &rBlock)
 
  728          llvm::zip(lBlock.
getArguments(), rBlock.getArguments())) {
 
  729       Value curArg = std::get<0>(argPair);
 
  730       Value otherArg = std::get<1>(argPair);
 
  738         markEquivalent(curArg, otherArg);
 
  744                                                 markEquivalent, flags,
 
  745                                                 checkCommutativeEquivalent))
 
  748       for (
auto successorsPair :
 
  750         Block *curSuccessor = std::get<0>(successorsPair);
 
  751         Block *otherSuccessor = std::get<1>(successorsPair);
 
  752         auto insertion = blocksMap.insert({curSuccessor, otherSuccessor});
 
  753         if (insertion.first->getSecond() != otherSuccessor)
 
  758     return llvm::all_of_zip(lBlock, rBlock, opsEquivalent);
 
  760   return llvm::all_of_zip(*lhs, *rhs, blocksEquivalent);
 
  768     return success(lhsValue == rhsValue ||
 
  769                    equivalentValues.lookup(lhsValue) == rhsValue);
 
  774     if (lhsRange.size() != rhsRange.size())
 
  778     auto lhsIt = lhsRange.begin();
 
  779     auto rhsIt = rhsRange.begin();
 
  780     for (; lhsIt != lhsRange.end(); ++lhsIt, ++rhsIt) {
 
  781       if (
failed(checkEquivalent(*lhsIt, *rhsIt)))
 
  784     if (lhsIt == lhsRange.end())
 
  792       llvm::sort(sortedValues, [](
Value a, 
Value b) {
 
  797     auto lhsSorted = sortValues({lhsIt, lhsRange.end()});
 
  798     auto rhsSorted = sortValues({rhsIt, rhsRange.end()});
 
  799     return success(lhsSorted == rhsSorted);
 
  802     auto insertion = equivalentValues.insert({lhsResult, rhsResult});
 
  806     assert(insertion.first->second == rhsResult &&
 
  807            "inconsistent OperationEquivalence state");
 
  817       [&](
Value lhsValue, 
Value rhsValue) -> LogicalResult {
 
  834         checkCommutativeEquivalent) {
 
  857   if (checkCommutativeEquivalent &&
 
  861     if (
failed(checkCommutativeEquivalent(lhsRange, rhsRange)))
 
  866       Value curArg = std::get<0>(operandPair);
 
  867       Value otherArg = std::get<1>(operandPair);
 
  868       if (curArg == otherArg)
 
  872       if (
failed(checkEquivalent(curArg, otherArg)))
 
  879     Value curArg = std::get<0>(resultPair);
 
  880     Value otherArg = std::get<1>(resultPair);
 
  884       markEquivalent(curArg, otherArg);
 
  890                               &std::get<1>(regionPair), checkEquivalent,
 
  891                               markEquivalent, flags))
 
  903       [&](
Value lhsValue, 
Value rhsValue) -> LogicalResult {
 
  919 template <
typename T>
 
  926                                            bool includeNested) {
 
  930   auto addOperationToHash = [&](
Operation *op) {
 
  942       for (
Block &block : region) {
 
  962     topOp->
walk(addOperationToHash);
 
  964     addOperationToHash(topOp);
 
  966   hash = hasher.result();
 
static Value getBase(Value v)
Looks through known "view-like" ops to find the base memref.
static MLIRContext * getContext(OpFoldResult val)
static void addDataToHash(llvm::SHA1 &hasher, const T &data)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
Attributes are known-constant values of operations.
MLIRContext * getContext() const
Return the context this attribute belongs to.
This class represents an argument of a Block.
This class provides an abstraction over the different types of ranges over Blocks.
Block represents an ordered list of Operations.
unsigned getNumArguments()
BlockArgListType getArguments()
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
const void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
MLIRContext is the top-level object for a collection of MLIR operations.
This class represents a contiguous range of mutable operand ranges, e.g.
MutableOperandRange join() const
Flatten all of the sub ranges into a single contiguous mutable operand range.
MutableOperandRangeRange(const MutableOperandRange &operands, NamedAttribute operandSegmentAttr)
Construct a range given a parent set of operands, and an I32 tensor elements attribute containing the...
This class provides a mutable adaptor for a range of operands.
OperandRange getAsOperandRange() const
Explicit conversion to an OperandRange.
void assign(ValueRange values)
Assign this range to the given values.
MutableOperandRange slice(unsigned subStart, unsigned subLen, std::optional< OperandSegment > segment=std::nullopt) const
Slice this range into a sub range, with the additional operand segment.
MutableArrayRef< OpOperand >::iterator end() const
void erase(unsigned subStart, unsigned subLen=1)
Erase the operands within the given sub-range.
void append(ValueRange values)
Append the given values to the range.
void clear()
Clear this range and erase all of the operands.
MutableArrayRef< OpOperand >::iterator begin() const
Iterators enumerate OpOperands.
MutableOperandRange(Operation *owner, unsigned start, unsigned length, ArrayRef< OperandSegment > operandSegments={})
Construct a new mutable range from the given operand, operand start index, and range length.
std::pair< unsigned, NamedAttribute > OperandSegment
A pair of a named attribute corresponding to an operand segment attribute, and the index within that ...
MutableOperandRangeRange split(NamedAttribute segmentSizes) const
Split this range into a set of contiguous subranges using the given elements attribute,...
OpOperand & operator[](unsigned index) const
Returns the OpOperand at the given index.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
std::optional< NamedAttribute > getNamed(StringRef name) const
Return the specified named attribute if present, std::nullopt otherwise.
void assign(const_iterator inStart, const_iterator inEnd)
Replaces the attributes with new list of attributes.
SmallVectorImpl< NamedAttribute >::const_iterator const_iterator
ArrayRef< NamedAttribute > getAttrs() const
Return all of the attributes on this operation.
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
Attribute get(StringAttr name) const
Return the specified attribute if present, null otherwise.
Attribute erase(StringAttr name)
Erase the attribute with the given name from the list.
std::optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
NamedAttrList & operator=(const SmallVectorImpl< NamedAttribute > &rhs)
NamedAttribute represents a combination of a name and an Attribute value.
This class represents an operand of an operation.
This is a value defined by a result of an operation.
This class adds property that the operation is commutative.
This class represents a contiguous range of operand ranges, e.g.
OperandRangeRange(OperandRange operands, Attribute operandSegments)
Construct a range given a parent set of operands, and an I32 elements attribute containing the sizes ...
OperandRange join() const
Flatten all of the sub ranges into a single contiguous operand range.
This class implements the operand iterators for the Operation class.
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
OperandRangeRange split(DenseI32ArrayAttr segmentSizes) const
Split this range into a set of contiguous subranges using the given elements attribute,...
OperationFingerPrint(Operation *topOp, bool includeNested=true)
bool compareOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
void insertOperands(unsigned index, ValueRange operands)
Insert the given operands into the operand list at the given 'index'.
OpOperand & getOpOperand(unsigned idx)
void setOperand(unsigned idx, Value value)
Block * getSuccessor(unsigned index)
unsigned getNumSuccessors()
void eraseOperands(unsigned idx, unsigned length=1)
Erase the operands starting at position idx and ending at position 'idx'+'length'.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
unsigned getNumRegions()
Returns the number of regions held by this operation.
Location getLoc()
The source location the operation was defined or derived from.
DictionaryAttr getRawDictionaryAttrs()
Return all attributes that are not stored as properties.
unsigned getNumOperands()
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
OperationName getName()
The name of an operation is the key identifier for it.
LogicalResult setPropertiesFromAttribute(Attribute attr, function_ref< InFlightDiagnostic()> emitError)
Set the properties from the provided attribute.
MutableArrayRef< OpOperand > getOpOperands()
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
void setOperands(ValueRange operands)
Replace the current operands of this operation with the ones provided in 'operands'.
SuccessorRange getSuccessors()
result_range getResults()
llvm::hash_code hashProperties()
Compute a hash for the op properties (if any).
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
unsigned getNumResults()
Return the number of results held by this operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
This class implements a use iterator for a range of operation results.
UseIterator(ResultRange results, bool end=false)
Initialize the UseIterator.
UseIterator & operator++()
This class implements the result iterators for the Operation class.
use_range getUses() const
Returns a range of all uses of results within this range, which is useful for iterating over all uses...
use_iterator use_begin() const
user_range getUsers()
Returns a range of all users.
ValueUserIterator< use_iterator, OpOperand > user_iterator
ResultRange(OpResult result)
use_iterator use_end() const
std::enable_if_t<!std::is_convertible< ValuesT, Operation * >::value > replaceUsesWithIf(ValuesT &&values, function_ref< bool(OpOperand &)> shouldReplace)
Replace uses of results of this range with the provided 'values' if the given callback returns true.
std::enable_if_t<!std::is_convertible< ValuesT, Operation * >::value > replaceAllUsesWith(ValuesT &&values)
Replace all uses of results of this range with the provided 'values'.
user_iterator user_begin()
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
PointerUnion< const Value *, OpOperand *, detail::OpResultImpl * > OwnerT
The type representing the owner of a ValueRange.
ValueRange(Arg &&arg LLVM_LIFETIME_BOUND)
An iterator over the users of an IRObject.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
void * getAsOpaquePointer() const
Methods for supporting PointerLikeTypeTraits.
Location getLoc() const
Return the location of this value.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Builder from ArrayRef<T>.
void eraseOperands(unsigned start, unsigned length)
Erase the operands held by the storage within the given range.
void setOperands(Operation *owner, ValueRange values)
Replace the operands contained in the storage with the ones provided in 'values'.
OperandStorage(Operation *owner, OpOperand *trailingOperands, ValueRange values)
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult checkEquivalent(Value lhsValue, Value rhsValue)
void markEquivalent(Value lhsResult, Value rhsResult)
LogicalResult checkCommutativeEquivalent(ValueRange lhsRange, ValueRange rhsRange)
DenseMap< Value, Value > equivalentValues
static bool isRegionEquivalentTo(Region *lhs, Region *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent, OperationEquivalence::Flags flags, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two regions (including their subregions) and return if they are equivalent.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two operations (including their regions) and return if they are equivalent.
static llvm::hash_code computeHash(Operation *op, function_ref< llvm::hash_code(Value)> hashOperands=[](Value v) { return hash_value(v);}, function_ref< llvm::hash_code(Value)> hashResults=[](Value v) { return hash_value(v);}, Flags flags=Flags::None)
Compute a hash for the given operation.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)
Take ownership of a set of regions that should be attached to the Operation.
SmallVector< Block *, 1 > successors
Successors of this operation and their respective operands.
SmallVector< Value, 4 > operands
void addOperands(ValueRange newOperands)
void addSuccessors(Block *successor)
Adds a successor to the operation sate. successor must not be null.
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
OperationState(Location location, StringRef name)
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.
Region * addRegion()
Create a region that should be attached to the operation.
LogicalResult setProperties(Operation *op, function_ref< InFlightDiagnostic()> emitError) const