18 #include "llvm/ADT/BitVector.h"
19 #include "llvm/Support/SHA1.h"
30 assign(attributes.begin(), attributes.end());
36 dictionarySorted.setPointerAndInt(attributes,
true);
46 std::optional<NamedAttribute> duplicate =
47 DictionaryAttr::findDuplicate(attrs, isSorted());
51 dictionarySorted.setPointerAndInt(
nullptr,
true);
57 DictionaryAttr::sortInPlace(attrs);
58 dictionarySorted.setPointerAndInt(
nullptr,
true);
60 if (!dictionarySorted.getPointer())
61 dictionarySorted.setPointer(DictionaryAttr::getWithSorted(context, attrs));
62 return dictionarySorted.getPointer().cast<DictionaryAttr>();
73 dictionarySorted.setPointerAndInt(
nullptr,
true);
78 dictionarySorted.setInt(attrs.empty() || attrs.back() < newAttribute);
79 dictionarySorted.setPointer(
nullptr);
80 attrs.push_back(newAttribute);
85 auto it = findAttr(*
this, name);
86 return it.second ? it.first->getValue() :
Attribute();
89 auto it = findAttr(*
this, name);
90 return it.second ? it.first->getValue() :
Attribute();
95 auto it = findAttr(*
this, name);
96 return it.second ? *it.first : std::optional<NamedAttribute>();
99 auto it = findAttr(*
this, name);
100 return it.second ? *it.first : std::optional<NamedAttribute>();
106 assert(value &&
"attributes may never be null");
110 auto it = findAttr(*
this, name);
114 Attribute oldValue = it.first->getValue();
115 if (it.first->getValue() != value) {
116 it.first->setValue(value);
119 dictionarySorted.setPointer(
nullptr);
126 it = findAttr(*
this, name.strref());
127 attrs.insert(it.first, {name, value});
129 dictionarySorted.setPointer(
nullptr);
134 assert(value &&
"attributes may never be null");
135 return set(mlir::StringAttr::get(value.
getContext(), name), value);
143 dictionarySorted.setPointer(
nullptr);
148 auto it = findAttr(*
this, name);
149 return it.second ? eraseImpl(it.first) :
Attribute();
153 auto it = findAttr(*
this, name);
154 return it.second ? eraseImpl(it.first) :
Attribute();
159 assign(rhs.begin(), rhs.end());
170 : location(location), name(name, location->getContext()) {}
173 : location(location), name(name) {}
180 : location(location), name(name),
181 operands(operands.begin(), operands.end()),
182 types(types.begin(), types.end()),
183 attributes(attributes.begin(), attributes.end()),
184 successors(successors.begin(), successors.end()) {
185 for (std::unique_ptr<Region> &r :
regions)
186 this->regions.push_back(std::move(r));
194 operands, types, attributes, successors, regions) {}
197 operands.append(newOperands.begin(), newOperands.end());
201 successors.append(newSuccessors.begin(), newSuccessors.end());
210 regions.push_back(std::move(region));
215 for (std::unique_ptr<Region> ®ion :
regions)
226 : isStorageDynamic(false), operandStorage(trailingOperands) {
227 numOperands = capacity = values.size();
228 for (
unsigned i = 0; i < numOperands; ++i)
229 new (&operandStorage[i])
OpOperand(owner, values[i]);
233 for (
auto &operand : getOperands())
234 operand.~OpOperand();
237 if (isStorageDynamic)
238 free(operandStorage);
245 for (
unsigned i = 0, e = values.size(); i != e; ++i)
246 storageOperands[i].set(values[i]);
255 unsigned newSize = operands.size();
256 if (newSize == length) {
258 for (
unsigned i = 0, e = length; i != e; ++i)
259 storageOperands[start + i].set(operands[i]);
264 if (newSize < length) {
265 eraseOperands(start + operands.size(), length - newSize);
266 setOperands(owner, start, newSize, operands);
270 auto storageOperands = resize(owner, size() + (newSize - length));
273 unsigned rotateSize = storageOperands.size() - (start + length);
274 auto rbegin = storageOperands.rbegin();
275 std::rotate(rbegin, std::next(rbegin, newSize - length), rbegin + rotateSize);
278 for (
unsigned i = 0, e = operands.size(); i != e; ++i)
279 storageOperands[start + i].set(operands[i]);
285 assert((start + length) <= operands.size());
286 numOperands -= length;
289 if (start != numOperands) {
290 auto *indexIt = std::next(operands.begin(), start);
291 std::rotate(indexIt, std::next(indexIt, length), operands.end());
293 for (
unsigned i = 0; i != length; ++i)
299 assert(eraseIndices.size() == operands.size());
302 int firstErasedIndice = eraseIndices.find_first();
303 if (firstErasedIndice == -1)
307 numOperands = firstErasedIndice;
308 for (
unsigned i = firstErasedIndice + 1, e = operands.size(); i < e; ++i)
309 if (!eraseIndices.test(i))
310 operands[numOperands++] = std::move(operands[i]);
311 for (
OpOperand &operand : operands.drop_front(numOperands))
312 operand.~OpOperand();
322 if (newSize <= numOperands) {
325 for (
unsigned i = newSize; i != numOperands; ++i)
327 numOperands = newSize;
328 return origOperands.take_front(newSize);
332 if (newSize <= capacity) {
333 OpOperand *opBegin = origOperands.data();
334 for (
unsigned e = newSize; numOperands != e; ++numOperands)
335 new (&opBegin[numOperands])
OpOperand(owner);
340 unsigned newCapacity =
341 std::max(
unsigned(llvm::NextPowerOf2(capacity + 2)), newSize);
347 std::uninitialized_move(origOperands.begin(), origOperands.end(),
348 newOperands.begin());
351 for (
auto &operand : origOperands)
352 operand.~OpOperand();
355 for (
unsigned e = newSize; numOperands != e; ++numOperands)
356 new (&newOperands[numOperands])
OpOperand(owner);
359 if (isStorageDynamic)
360 free(operandStorage);
363 operandStorage = newOperandStorage;
364 capacity = newCapacity;
365 isStorageDynamic =
true;
377 assert(!empty() &&
"range must not be empty");
378 return base->getOperandNumber();
394 const OwnerT &owner = getBase();
397 std::accumulate(sizeData.begin(), sizeData.end(), 0));
400 OperandRange OperandRangeRange::dereference(
const OwnerT &
object,
403 uint32_t startIndex =
404 std::accumulate(sizeData.begin(), sizeData.begin() + index, 0);
405 return OperandRange(
object.first + startIndex, *(sizeData.begin() + index));
414 Operation *owner,
unsigned start,
unsigned length,
416 : owner(owner), start(start), length(length),
417 operandSegments(operandSegments.begin(), operandSegments.end()) {
418 assert((start + length) <= owner->
getNumOperands() &&
"invalid range");
426 std::optional<OperandSegment> segment)
const {
427 assert((subStart + subLen) <= length &&
"invalid sub-range");
431 subSlice.operandSegments.push_back(*segment);
440 updateLength(length + values.size());
446 if (length != values.size())
447 updateLength(values.size());
462 assert((subStart + subLen) <= length &&
"invalid sub-range");
466 updateLength(length - subLen);
488 void MutableOperandRange::updateLength(
unsigned newLength) {
489 int32_t diff = int32_t(newLength) - int32_t(length);
496 segments[segment.first] += diff;
497 segment.second.setValue(
499 owner->
setAttr(segment.second.getName(), segment.second.getValue());
509 OwnerT(operands, operandSegmentAttr), 0,
513 return getBase().first;
524 uint32_t startIndex =
525 std::accumulate(sizeData.begin(), sizeData.begin() + index, 0);
526 return object.first.slice(
527 startIndex, *(sizeData.begin() + index),
558 : it(end ? results.end() : results.begin()), endIt(results.end()) {
561 skipOverResultsWithNoUsers();
567 if (use != (*it).use_end())
569 if (use == (*it).use_end()) {
571 skipOverResultsWithNoUsers();
576 void ResultRange::UseIterator::skipOverResultsWithNoUsers() {
577 while (it != endIt && (*it).use_empty())
585 use = (*it).use_begin();
603 :
ValueRange(values.begin().getBase(), values.size()) {}
605 :
ValueRange(values.getBase(), values.size()) {}
610 if (
const auto *value = owner.dyn_cast<
const Value *>())
611 return {value + index};
612 if (
auto *operand = owner.dyn_cast<
OpOperand *>())
613 return {operand + index};
617 Value ValueRange::dereference_iterator(
const OwnerT &owner, ptrdiff_t index) {
618 if (
const auto *value = owner.dyn_cast<
const Value *>())
620 if (
auto *operand = owner.dyn_cast<
OpOperand *>())
621 return operand[index].get();
636 llvm::hash_code hash = llvm::hash_combine(
643 operandStorage.append(operands.begin(), operands.end());
644 llvm::sort(operandStorage, [](
Value a,
Value b) ->
bool {
647 operands = operandStorage;
649 for (
Value operand : operands)
650 hash = llvm::hash_combine(hash, hashOperands(operand));
654 hash = llvm::hash_combine(hash, hashResults(result));
664 auto blocksEquivalent = [&](
Block &lBlock,
Block &rBlock) {
670 auto insertion = blocksMap.insert({&lBlock, &rBlock});
671 if (insertion.first->getSecond() != &rBlock)
675 llvm::zip(lBlock.
getArguments(), rBlock.getArguments())) {
676 Value curArg = std::get<0>(argPair);
677 Value otherArg = std::get<1>(argPair);
685 markEquivalent(curArg, otherArg);
691 markEquivalent, flags))
694 for (
auto successorsPair :
696 Block *curSuccessor = std::get<0>(successorsPair);
697 Block *otherSuccessor = std::get<1>(successorsPair);
698 auto insertion = blocksMap.insert({curSuccessor, otherSuccessor});
699 if (insertion.first->getSecond() != otherSuccessor)
704 return llvm::all_of_zip(lBlock, rBlock, opsEquivalent);
706 return llvm::all_of_zip(*lhs, *rhs, blocksEquivalent);
714 return success(lhsValue == rhsValue ||
715 equivalentValues.lookup(lhsValue) == rhsValue);
718 auto insertion = equivalentValues.insert({lhsResult, rhsResult});
722 assert(insertion.first->second == rhsResult &&
723 "inconsistent OperationEquivalence state");
766 llvm::sort(sortedValues, [](
Value a,
Value b) {
789 lhsOperandStorage = sortValues(lhsOperands);
790 lhsOperands = lhsOperandStorage;
791 rhsOperandStorage = sortValues(rhsOperands);
792 rhsOperands = rhsOperandStorage;
795 for (
auto operandPair : llvm::zip(lhsOperands, rhsOperands)) {
796 Value curArg = std::get<0>(operandPair);
797 Value otherArg = std::get<1>(operandPair);
798 if (curArg == otherArg)
802 if (
failed(checkEquivalent(curArg, otherArg)))
808 Value curArg = std::get<0>(resultPair);
809 Value otherArg = std::get<1>(resultPair);
813 markEquivalent(curArg, otherArg);
819 &std::get<1>(regionPair), checkEquivalent,
820 markEquivalent, flags))
845 template <
typename T>
862 for (
Block &block : region) {
880 hash = hasher.result();
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.
unsigned getArgNumber() const
Returns the number of this argument.
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 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.
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.
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.
MutableOperandRange(Operation *owner, unsigned start, unsigned length, ArrayRef< OperandSegment > operandSegments=std::nullopt)
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,...
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.
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
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)
Operation is the basic unit of execution within MLIR.
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'.
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.
unsigned getNumOperands()
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.
DictionaryAttr getAttrDictionary()
Return all of the attributes on this operation as a DictionaryAttr.
OperationName getName()
The name of an operation is the key identifier for it.
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()
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.
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.
Block * getParentBlock()
Return the Block in which this Value is defined.
Location getLoc() const
Return the location of this value.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Builder from ArrayRef<T>.
This class provides the implementation for an operation result.
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)
Include the generated interface declarations.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
LogicalResult checkEquivalent(Value lhsValue, Value rhsValue)
void markEquivalent(Value lhsResult, Value rhsResult)
DenseMap< Value, Value > equivalentValues
This class represents an efficient way to signal success or failure.
static bool isRegionEquivalentTo(Region *lhs, Region *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent, OperationEquivalence::Flags flags)
Compare two regions (including their subregions) 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.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None)
Compare two operations (including their regions) and return if they are equivalent.
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)
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
OperationState(Location location, StringRef name)
Region * addRegion()
Create a region that should be attached to the operation.