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");
129 return set(mlir::StringAttr::get(value.
getContext(), name), value);
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();
179 for (std::unique_ptr<Region> &r :
regions)
180 this->regions.push_back(std::move(r));
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]);
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) {
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));
412OperandRange OperandRangeRange::dereference(
const OwnerT &
object,
415 uint32_t startIndex = llvm::sum_of(sizeData.take_front(
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);
457 owner->insertOperands(start + length, values);
458 updateLength(length + values.size());
463 owner->setOperands(start, length, values);
464 if (length != values.size())
465 updateLength(values.size());
471 owner->setOperand(start, value);
473 owner->setOperands(start, length, value);
480 assert((subStart + subLen) <= length &&
"invalid sub-range");
483 owner->eraseOperands(start + subStart, subLen);
484 updateLength(length - subLen);
490 owner->eraseOperands(start, length);
497 return owner->getOperands().slice(start, length);
506 return owner->getOpOperands().slice(start, length);
515void 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");
532 return owner->getOpOperand(start +
index);
536 return owner->getOpOperands().slice(start, length).begin();
540 return owner->getOpOperands().slice(start, length).end();
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();
618void 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);
660Value 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;
682 llvm::hash_code hash =
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 ||
774 if (lhsRange.size() != rhsRange.size())
778 auto lhsIt = lhsRange.begin();
779 auto rhsIt = rhsRange.begin();
780 for (; lhsIt != lhsRange.end(); ++lhsIt, ++rhsIt) {
784 if (lhsIt == lhsRange.end())
797 auto lhsSorted = sortValues({lhsIt, lhsRange.end()});
798 auto rhsSorted = sortValues({rhsIt, rhsRange.end()});
799 return success(lhsSorted == rhsSorted);
806 assert(insertion.first->second == rhsResult &&
807 "inconsistent OperationEquivalence state");
817 [&](
Value lhsValue,
Value rhsValue) -> LogicalResult {
834 checkCommutativeEquivalent) {
840 lhs->getRawDictionaryAttrs() !=
rhs->getRawDictionaryAttrs())
843 if (
lhs->getName() !=
rhs->getName() ||
844 lhs->getNumRegions() !=
rhs->getNumRegions() ||
845 lhs->getNumSuccessors() !=
rhs->getNumSuccessors() ||
846 lhs->getNumOperands() !=
rhs->getNumOperands() ||
847 lhs->getNumResults() !=
rhs->getNumResults())
850 !(
lhs->getName().compareOpProperties(
lhs->getPropertiesStorage(),
851 rhs->getPropertiesStorage())))
857 if (checkCommutativeEquivalent &&
859 auto lhsRange =
lhs->getOperands();
860 auto rhsRange =
rhs->getOperands();
861 if (failed(checkCommutativeEquivalent(lhsRange, rhsRange)))
865 for (
auto operandPair : llvm::zip(
lhs->getOperands(),
rhs->getOperands())) {
866 Value curArg = std::get<0>(operandPair);
867 Value otherArg = std::get<1>(operandPair);
868 if (curArg == otherArg)
872 if (failed(checkEquivalent(curArg, otherArg)))
878 for (
auto resultPair : llvm::zip(
lhs->getResults(),
rhs->getResults())) {
879 Value curArg = std::get<0>(resultPair);
880 Value otherArg = std::get<1>(resultPair);
884 markEquivalent(curArg, otherArg);
888 for (
auto regionPair : llvm::zip(
lhs->getRegions(),
rhs->getRegions()))
890 &std::get<1>(regionPair), checkEquivalent,
891 markEquivalent, flags))
903 [&](
Value lhsValue,
Value rhsValue) -> LogicalResult {
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.
false
Parses a map_entries map type from a string format back into its numeric value.
static void addDataToHash(llvm::SHA1 &hasher, const T &data)
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.
Operation * getOwner() const
Returns the owning operation.
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)
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.
unsigned getNumSuccessors()
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
DictionaryAttr getRawDictionaryAttrs()
Return all attributes that are not stored as properties.
unsigned getNumOperands()
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
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< Region > getRegions()
Returns the regions held by this operation.
result_type_range getResultTypes()
operand_range getOperands()
Returns an iterator on the underlying Value's.
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),...
Block * getSuccessor(unsigned index)
SuccessorRange getSuccessors()
result_range getResults()
llvm::hash_code hashProperties()
Compute a hash for the op properties (if any).
OpaqueProperties getPropertiesStorage()
Returns the properties storage.
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.
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.
iterator_range< user_iterator > user_range
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
user_iterator user_begin()
iterator_range< use_iterator > use_range
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'.
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)
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)
void eraseOperands(unsigned start, unsigned length)
Erase the operands held by the storage within the given range.
MutableArrayRef< OpOperand > getOperands()
Get the operation operands held by the storage.
unsigned size()
Return the number of operands held in the storage.
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.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref
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.
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.
void addRegions(MutableArrayRef< std::unique_ptr< Region > > regions)
Take ownership of a set of regions that should be attached to the Operation.
MLIRContext * getContext() const
Get the context held by this operation state.
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.
SmallVector< Type, 4 > types
Types of the results of this operation.
Region * addRegion()
Create a region that should be attached to the operation.
LogicalResult setProperties(Operation *op, function_ref< InFlightDiagnostic()> emitError) const